Count Number of Teams - Javascript - javascript

I'm trying to solve the problem below in JavaScript.
There are n soldiers standing in a line. Each soldier is assigned a
unique rating value.
You have to form a team of 3 soldiers amongst them under the following
rules:
Choose 3 soldiers with index (i, j, k) with rating (rating[i],
rating[j], rating[k]). A team is valid if: (rating[i] < rating[j] <
rating[k]) or (rating[i] > rating[j] > rating[k]) where (0 <= i < j <
k < n). Return the number of teams you can form given the conditions.
(soldiers can be part of multiple teams).
Example:
Input: rating = [2,5,3,4,1]
Output: 3
Explanation: We can form three teams given the conditions. (2,3,4), (5,4,1), (5,3,1).
My idea is to keep an array of possible combinations, when I reach 3 elements in the combinations, I increment my res variable. My attempt:
var numTeams = function(rating) {
let res = 0;
if(!rating || rating.length < 3) return res;
let combinations = [];
for(let i=0; i<rating.length; i++) {
const size = combinations.length;
for(let j=0; j<size; j++) {
const temp = combinations[j];
if(temp.length === 1 && temp[0] !== rating[i]) {
temp.push(rating[i]);
combinations.push(temp);
} else {
if(temp[0] < temp[1] && temp[1] < rating[i])
res++;
else if(temp[0] > temp[1] && temp[1] > rating[i])
res++;
}
}
combinations.push([rating[i]]);
}
return res;
};
It is returning 2 for the example input, not 3.

I suggest to use three encapsulated for loops. By initializing the indexes with the value of the current value of the index of the outer loop, e.g. k = i, the condition (0 <= i < j < k < n) is implicitly fulfilled.
Within the innermost loop, you can then check if the conditions to be a combination is true for the current set of soldiers by checking if rating[i] < rating[k] && rating[k] < rating[l] or rating[i] > rating[k] && rating[k] > rating[l] and add the values to the array holding the valid combinations.
At the end, the length of the array holding the valid combinations is printed:
var rating = [2,5,3,4,1];
var combinations = [];
for (i = 0; i < rating.length; i = i+1) {
for (k = i; k < rating.length; k = k+1) {
for (l = k; l < rating.length; l = l+1) {
if (rating[i] < rating[k] && rating[k] < rating[l]) {
combinations.push([rating[i], rating[k], rating[l]]);
}
if (rating[i] > rating[k] && rating[k] > rating[l]) {
combinations.push([rating[i], rating[k], rating[l]]);
}
}
}
}
console.log(combinations);
console.log(combinations.length);
Output:
[ [ 2, 3, 4 ], [ 5, 3, 1 ], [ 5, 4, 1 ] ]
3

For better performance compared to the three for loops provided in answer https://stackoverflow.com/a/64921918/9240674, i also iterate over the rating array only once now. An array variations holds all variations that may become a valid combination. The entries consist of the function which is used to determine whether the variation is a valid combination and the ratings. With each iteration over the rating array, the new rating[i] is checked against all variations if it might complete the currently checked variation to become a valid combination. If so, the ratings of the current variation[k] are stored in combinations array.
var rating = [2,5,3,4,1];
var variations = [];
var combinations = [];
function less_than(a, b) {
return a < b;
}
function greater_than(a, b) {
return a > b;
}
for (i = 0; i < rating.length; i = i + 1) {
var duplications = [];
for (k = 0; k < variations.length; k = k + 1) {
if (variations[k].ratings.length < 3) {
if (variations[k].comparemethod(rating[i],variations[k].ratings[variations[k].ratings.length-1])) {
// Duplicate current (incomplete) variation
duplications.push({"comparemethod": variations[k].comparemethod, "ratings": variations[k].ratings.slice()});
// Add the current rating to the current variation
variations[k].ratings.push(rating[i]);
}
if (variations[k].ratings.length == 3) {
// we found a valid combination
combinations.push(variations[k].ratings);
}
}
}
// add entries which needed to be duplicated to the variations
variations = variations.concat(duplications);
// add the current rating to the variations
variations.push({comparemethod: less_than, ratings: [rating[i]]});
variations.push({comparemethod: greater_than, ratings: [rating[i]]});
}
console.log(JSON.stringify(combinations));
console.log(combinations.length);
Output:
[[2,3,4],[5,3,1],[5,4,1]]
3

Related

Largest Triple Products without using sort?

I implemented the Largest Triple Products algorithm, but I use sort which makes my time complexity O(nlogn). Is there a way to implement it without a temporary sorted array?
The problem:
You're given a list of n integers arr[0..(n-1)]. You must compute a list output[0..(n-1)] such that, for each index i (between 0 and n-1, inclusive), output[i] is equal to the product of the three largest elements out of arr[0..i] (or equal to -1 if i < 2, as arr[0..i] then includes fewer than three elements).
Note that the three largest elements used to form any product may have the same values as one another, but they must be at different indices in arr.
Example:
var arr_2 = [2, 4, 7, 1, 5, 3];
var expected_2 = [-1, -1, 56, 56, 140, 140];
My solution:
function findMaxProduct(arr) {
// Write your code here
if(!arr || arr.length === 0) return [];
let helper = arr.slice();
helper.sort((a,b)=>a-b); // THIS IS THE SORT
let ans = [];
let prod = 1;
for(let i=0; i<arr.length; i++) {
if(i < 2) {
prod *= arr[i];
ans.push(-1);
}
else {
if(i === 3) {
prod *= arr[i];
ans.push(prod);
} else if(arr[i] < helper[0]) {
ans.push(prod);
} else {
const min = helper.shift();
prod /= min;
prod *= arr[i];
ans.push(prod);
}
}
}
return ans;
}
Thanks
You don't need to sort it. You just maintain an array of the largest three elements at each index.
For the first three elements it is simple you just assign the product of them to the third element in the result.
For the next elements, you add the current element to the three-largest-element-array and sort it and take the elements from 1 to 3 ( the largest three ) and assign the product of those at that index in result array. Then update the three-element-array with largest three.
Complexity :
This sort and slice of three-element-array should be O(1) because each time atmost 4 elements are there in the array.
Overall complexity is O(n).
You can do it as follows :
function findMaxProduct(arr) {
if(!arr) return [];
if (arr.length < 3) return arr.slice().fill(-1)
let t = arr.slice(0,3)
let ans = arr.slice().fill(-1,0,2) //fill first two with -1
ans[2] = t[0]*t[1]*t[2];
for(let i=3; i<arr.length; i++) {
t.push(arr[i]);
t = t.sort().slice(1,4);
ans[i] = t[0]*t[1]*t[2];
}
return ans;
}
I am keeping the array ordered (manually). Then just get the first 3 elements.
function findMaxProduct(arr) {
let results = [];
let heap = [];
for (let i = 0; i < arr.length; i++) {
// Insert the new element in the correct position
for (let j = 0; j < heap.length; j++) {
if (arr[i] >= heap[j]) {
heap.splice(j, 0, arr[i]);
break;
}
}
// No position found, insert at the end
if (heap.length != i + 1) {
heap.push(arr[i]);
}
if (i < 2) {
results.push(-1);
} else {
results.push(heap[0] * heap[1] * heap[2]);
}
}
return results;
}
You can make an array that holds three currently largest integers, and update that array as you passing through original array. That's how you will always have three currently largest numbers and you will be able to solve this with O(n) time complexity.
I think there's a faster and more efficient way to go about this. This is a similar thought process as #Q2Learn, using Python; just faster:
def findMaxProduct(arr):
#create a copy of arr
solution = arr.copy()
# make first 2 elements -1
for i in range(0,2):
solution[i] = -1
#for each item in copy starting from index 2, multiply item from 2 indices b'4 (notice how each index of arr being multiplied is reduced by 2, 1 and then 0, to accommodate each move)
for i in range(2, len(arr)):
solution[i] = arr[i-2] * arr[i-1] * arr[i]
return solution
check = findMaxProduct(arr)
print(check)
Single Scan Algorithm O(n)
We don't need to necessarily sort the given array to find the maximum product. Instead, we can only find the three largest values (x, y, z) in the given stage of iteration:
JavaScript:
function findMaxProduct(arr) {
let reults = []
let x = 0
let y = 0
let z = 0
for(let i=0; i<arr.length; i++) {
n = arr[i]
if (n > x) {
z = y
y = x
x = n
}
if (n < x && n > y) {
z = y
y = n
}
if (n < y && n > z) {
z = n
}
ans = x*y*z
if (ans === 0) {
results.push(-1)
} else {
results.push(ans)
}
return ans;
}
Python:
def findMaxProduct(arr):
results = []
if not arr:
return []
x = 0
y = 0
z = 0
for i, n in enumerate(arr):
if n > x:
z = y
y = x
x = n
if n < x and n > y:
z = y
y = n
if n < y and n > z:
z = n
ans = x*y*z
if ans == 0:
results.append(-1)
else:
results.append(ans)
print(results)
public int[] LargestTripleProducts(int[] input)
{
var ansArr = new int[input.Length];
var firstLargetst = input[0];
var secondLargetst = input[1];
ansArr[0] = ansArr[1] = -1;
for (int i = 2; i < input.Length; i++)
{
ansArr[i] = firstLargetst * secondLargetst * input[i];
if (firstLargetst < input[i] && firstLargetst < secondLargetst)
{
firstLargetst= input[i];
continue;
}
if (secondLargetst < input[i] && secondLargetst < firstLargetst)
{
secondLargetst= input[i];
}
}
return ansArr;
}
Python solution based on #SomeDude answer above. See explanation there.
def findMaxProduct(arr):
if not arr:
return None
if len(arr) < 3:
for i in range(len(arr)):
arr[i] = -1
return arr
three_largest_elem = arr[0:3]
answer = arr.copy()
for i in range(0, 2):
answer[i] = -1
answer[2] = three_largest_elem[0] * three_largest_elem[1] * three_largest_elem[2]
for i in range(3, len(arr)):
three_largest_elem.append(arr[i])
three_largest_elem = sorted(three_largest_elem)
three_largest_elem = three_largest_elem[1:4]
answer[i] = three_largest_elem[0] * three_largest_elem[1] * three_largest_elem[2]
return answer #Time: O(1) n <= 4, to Overall O(n) | Space: O(1)
Python has it's in-built package heapq, look at it for it.
Credit: Martin
> Helper function for any type of calculations
import math
> Heap algorithm
import heapq
> Create empty list to append output values
output = []
def findMaxProduct(arr):
out = []
h = []
for e in arr:
heapq.heappush(h, e)
if len(h) < 3:
out.append(-1)
else:
if len(h) > 3:
heapq.heappop(h)
out.append(h[0] * h[1] * h[2])
return out
Hope this helps!

How do I utilize the length of an array in a function (in JavaScript) when the array is being passed as a parameter and the length does not exist yet?

I'm trying to write a function that takes an array of strings(strarr) and an integer(k) as parameters and returns the longest string made up of k amount of consecutive strings within the array, not separated by commas. I need to call on strarr.length quite often during the function, but I keep getting an error saying that it cannot read that parameter's length.
This is my first time dealing with this issue and I have not found great internet search results for solutions. I suspect that I'm missing something very obvious. I have tried pushing the values of the strarr array parameter into a new array and still no luck.
So if I had const = ['apple','pineapple','banana','strawberry'] passed as my strarr parameter and 2 passed as k, then it should return 'bananastrawberry' because it is the longest consecutive pair of strings within the array.
const arr = ['apple', 'pineapple', 'banana', 'strawberry']
function longestConsec(strarr, k) {
if (strarr.length === 0) {
return "";
} else if (k > strarr.length) {
return "";
} else if (k <= 0) {
return "";
}
let longest = "";
let strLeng = 0;
for (let i = 0; i < strarr.length; i++) {
for (let j = i + (k - 1); j > 0; j--) {
strLeng += strarr[j].length;
}
if (strLeng > longest.length) {
longest = strarr.slice(i, (i + k)).join("");
}
}
return longest;
}
console.log(longestConsec(arr, 2))
As mentioned, you are trying to access an index that doesn't exist in you array.
A quick fix might be:
const arr = ['apple', 'pineapple', 'banana', 'strawberry']
function longestConsec(strarr, k) {
if (strarr.length === 0) {
return "";
} else if (k > strarr.length) {
return "";
} else if (k <= 0) {
return "";
}
let longest = "";
let strLeng = 0;
for (let i = 0; i < strarr.length; i++) {
for (let j = i + (k - 1); j > 0; j--) {
if (j >= strarr.length) {
break;
}
strLeng += strarr[j].length;
}
if (strLeng > longest.length) {
longest = strarr.slice(i, (i + k)).join("");
}
}
return longest;
}
console.log(longestConsec(arr, 2))
But I would suggest to see if there is better solution than adding a break statement.
Mistakes you did
In the inner for loop, for (let j = i + (k - 1); j > 0; j--), you're counting from i + k - 1. But what if i is the last index of array (strarr.length == 10 and i == 9) and k == 2? Then your loop starts at j = 9 + 2 - 1 = 10 and one line below, you try to do strLeng += strarr[10].length, but strarr[10] is not defined.
It also seems unnecessary to create strings before you're done finding the longest one. You could instead just remember start index of your last longest string instead.
How to make it better
Let's look at the requirements. For each i in the array, you want to merge k consecutive strings and keep the longest combination. From that follows:
i + k - 1 must never be larger than strarr.length. Since the i is the only variable here, we need to limit it by only looping up to strarr.length - k + 1.
If k == strarr.length, there is only one string you can make - strarr.join("")
Finally, there's an idea that you probably do not need nested loop at all. For every i, you simply subtract the length of the last string in your current window and add a new one. See image:
So with that in mind, I would propose following version of your code:
function longestConsec(strarr, k) {
// Cannot create any joined string with k greater than length
if(strarr.length < k) {
return "";
}
else if(k <= 0) {
return "";
}
else if(strarr.length == k) {
return strarr.join("");
}
let longestIndex = -1;
let longestLength = 0;
// length of our current group of strings
let currentLength = 0;
const maxLen = strarr.length;
for(let i=0; i<maxLen; ++i) {
// Forget the first strings length
if(i >= k) {
currentLength -= strarr[i-k].length;
}
// add the current strings length
currentLength += strarr[i].length;
// check if this is the largest length and save it's index
// Only possible after processing at least k strings
// Eg when i==1, we already went through 2 strings at this point
if(i >= k-1) {
if(currentLength > longestLength) {
const startIndex = i-k+1;
longestLength = currentLength;
longestIndex = startIndex;
}
}
}
return strarr.slice(longestIndex, (longestIndex + k)).join("");
}
Here's a jsFiddle test: https://jsfiddle.net/32g5oqd1/2/

Javascript Program for find common elements in two array

Recently I had an interview question as follows:
Let us consider we have two sorted arrays of different length. Need to find the common elements in two arrays.
var a=[1,2,3,4,5,6,7,8,9,10];
var b = [2,4,5,7,11,15];
for(var i=0;i<a.length;i++){
for(var j=0;j<b.length;j++){
if(a[i]==b[j]){
console.log(a[i],b[j])
}
}
}
I wrote like above. The interviewer said let now assume a have 2000 elements and b have 3000 elements. Then how you wrote in a more efficient way?
Please explain your answers with sample code. So I can understand more clearly.
The easiest way!!
var a = [1,2,3,4,5,6,7,8,9,10];
var b = [2,4,5,7,11,15];
for(let i of a){
if(b.includes(i)){
console.log(i)
}
}
--------- OR --------------
var c = a.filter(value => b.includes(value))
console.log(c)
Since the arrays are sorted, binary search is the key.
Basically, you're searching an item in an array.
You compare the item against the middle index of the array (length / 2)
If both are equal, you found it.
If item is inferior than the one at the middle index of the array, compare item against the index being at index length / 4 -> ((0 + length / 2) / 2), if it's inferior, at index ((length / 2) + length) / 2 (the middle of upper part) and so on.
That way, if in example you have to search item in a 40 000 length array, at worse, you find out that item isn't in the array with 16 comparisons :
I'm searching for "something" in an array with 40 000 indexes, minimum index where I can find it is 0, the maximum is 39999.
"something" > arr[20000]. Let's assume that. I know that now the minimum index to search is 20001 and the maximum is 39999. I'm now searching for the middle one, (20000 + 39999) / 2.
Now, "something" < arr[30000], it limits the search from indexes 20001 to 29999. (20000 + 30000) / 2 = 25000.
"something" > arr[25000], I have to search from 25001 to 29999. (25000 + 30000) / 2 = 27500
"something" < arr[27500], I have to search from 25001 to 27499. (25000 + 27500) / 2 = 26250
"something" > arr[26250], I have to search from 26251 to 27499. (26250 + 27500) / 2 = 26875
"something" < arr[26875], I have to search from 26251 to 26874. (26250 + 26875) / 2 = 26563
And so on... Of course, you have to round and stuff to avoid floating indexes
var iteration = 1;
function bSearch(item, arr)
{
var minimumIndex = 0;
var maximumIndex = arr.length - 1;
var index = Math.round((minimumIndex + maximumIndex) / 2);
while (true)
{
++iteration;
if (item == arr[index])
{
arr.splice(0, minimumIndex);
return (true);
}
if (minimumIndex == maximumIndex)
{
arr.splice(0, minimumIndex);
return (false);
}
if (item < arr[index])
{
maximumIndex = index - 1;
index = Math.ceil((minimumIndex + maximumIndex) / 2);
}
else
{
minimumIndex = index + 1;
index = Math.floor((minimumIndex + maximumIndex) / 2);
}
}
}
var arrA;
var arrB;
for (var i = 0; i < arrA.length; ++i)
{
if (bSearch(arrA[i], arrB))
console.log(arrA[i]);
}
console.log("number of iterations : " + iteration);
You could use a nested approach by checking the index of each array and find the values by incrementing the indices. If equal values are found, increment both indices.
Time complexity: max. O(n+m), where n is the length of array a and m is the length of array b.
var a = [1, 2, 3, 4, 5, 6, 8, 10, 11, 15], // left side
b = [3, 7, 8, 11, 12, 13, 15, 17], // right side
i = 0, // index for a
j = 0; // index for b
while (i < a.length && j < b.length) { // prevent running forever
while (a[i] < b[j]) { // check left side
++i; // increment index
}
while (b[j] < a[i]) { // check right side
++j; // increment
}
if (a[i] === b[j]) { // check equalness
console.log(a[i], b[j]); // output or collect
++i; // increment indices
++j;
}
}
since both arrays are sorted just save the lastest match index . then start your inner loop from this index .
var lastMatchedIndex = 0;
for(var i=0;i<a.length;i++){
for(var j=lastMatchIndex ;j<b.length;j++){
if(a[i]==b[j]){
console.log(a[i],b[j]);
lastMatchedIndex = j;
break;
}
}
}
=================
UPDATE :
As Xufox mentioned in comments if a[i] is lower than b[i] then u have break loop since it has no point to continue the loop .
var lastMatchedIndex = 0;
for(var i=0;i<a.length;i++){
if(a[i]<b[i]){
break;
}
for(var j=lastMatchIndex ;j<b.length;j++){
if(a[i]==b[j]){
console.log(a[i],b[j]);
lastMatchedIndex = j;
break;
}
if(a[i]<b[j]){
lastMatchedIndex = j;
break;
}
}
}
An optimal strategy would be one where you minimize the amount of comparisons and array readings.
Theoretically what you want is to alternate which list you are progressing through so as to avoid unnecessary comparisons. Giving that the lists are sorted we know that no number to the left of any index in a list can ever be smaller than the current index.
Assuming the following list A = [1,5], list B = [1,1,3,4,5,6] and indexes a and b both starting at 0, you would want your code to go like this:
A[a] == 1, B[b] == 1
A[a] == B[b] --> add indexes to results and increase b (B[b] == 1)
A[a] == B[b] --> add indexes to results and increase b (B[b] == 3)
A[a] < B[b] --> don't add indexes to results and increase a (A[a] == 5)
A[a] > B[b] --> don't add indexes to results and increase b (B[b] == 4)
A[a] > B[b] --> don't add indexes to results and increase b (B[b] == 5)
A[a] == B[b] --> add indexes to results and increase b (B[b] == 6)
A[a] < B[b] --> don't add indexes to results and increase a (A is at the end, so we terminate and return results)
Below is my JavaScript performing the above described algorithm:
//Parameters
var listA = [];
var listB = [];
//Parameter initialization
(function populateListA() {
var value = 0;
while (listA.length < 200) {
listA.push(value);
value += Math.round(Math.random());
}
})();
(function populateListB() {
var value = 0;
while (listB.length < 300) {
listB.push(value);
value += Math.round(Math.random());
}
})();
//Searcher function
function findCommon(listA, listB) {
//List of results to return
var results = [];
//Initialize indexes
var indexA = 0;
var indexB = 0;
//Loop through list a
while (indexA < listA.length) {
//Get value of A
var valueA = listA[indexA];
var result_1 = void 0;
//Get last result or make a first result
if (results.length < 1) {
result_1 = {
value: valueA,
indexesInA: [],
indexesInB: []
};
results.push(result_1);
}
else {
result_1 = results[results.length - 1];
}
//If higher than last result, make new result
//Push index to result
if (result_1.value < valueA) {
//Make new object
result_1 = {
value: valueA,
indexesInA: [indexA],
indexesInB: []
};
//Push to list
results.push(result_1);
}
else {
//Add indexA to list
result_1.indexesInA.push(indexA);
}
//Loop through list b
while (indexB < listB.length) {
//Get value of B
var valueB = listB[indexB];
//If b is less than a, move up list b
if (valueB < valueA) {
indexB++;
continue;
}
//If b is greather than a, break and move up list a
if (valueB > valueA) {
break;
}
//If b matches a, append index to result
result_1.indexesInB.push(indexB);
//Move up list B
indexB++;
}
//Move up list A
indexA++;
}
//Return all results with values in both lines
return results.filter(function (result) { return result.indexesInB.length > 0; });
}
//Run
var result = findCommon(listA, listB);
//Output
console.log(result);
We could iterate one array and find the duplicate in the other, but each time we find a match, we move to the matched element + 1 for the next iteration in the nested loop. It works because both arrays are sorted. So each match the array to compare is shorter (from left to right).
We could also break the nested loop when the element of the second array is greater than the first (it's shorter from right to left), because we will never find a match (since the array is ordered, there are only greater values remaining), here and example finding duplicates in two arrays of 10k elements, takes roughly 15 miliseconds:
var arr = [];
var arr2 = [];
for(let i = 0; i<9999; i++){
arr.push(i);
arr2.push(i+4999)
}
var k = 0;//<-- the index we start to compare
var res = [];
for (let i = 0; i < arr2.length; i++) {
for (let j = k; j < arr.length; j++) {
if (arr2[i] === arr[j]) {
res.push(arr2[i]);
k = j + 1;//<-- updates the index
break;
} else if (arr[j] > arr2[i]) {//<-- there is no need to keep going
break;
}
}
}
console.log(res.length)
I did not print res, because it has 5000 elements.
You can build a hash with first array (irrespective of they are sorted or not) and iterate the second array and check for existence in the hash!
let arr1 = [10, 20, 30, 40, 50, 60, 70, 80, 90, 100, 110, 120, 130, 140, 150],
arr2 = [15,30,45,60,75,90,105,120,135,150,165]
hash = arr1.reduce((h,e)=> (h[e]=1, h), {}), //iterate first array once
common = arr2.filter(v=>hash[v]); //iterate secod array once
console.log('Cpmmon elements: ', common);
Not sure but this may help
let num1 = [2, 3, 6, 6, 5];
let num2 = [1, 3, 6, 4];
var array3 = num1.filter((x) => {
return num2.indexOf(x) != -1
})
console.log(array3);
I sometimes find it convenient to turn one list into a hashset.
var hashA = {};
for(var i=0; i<a.length; i++) {hashA[a[i]] = true;}
then you can search the hashset.
for(var i=0; i<b.length; i++) {if(hashA[b[i]]) {console.log(b[i]);}}
This isnt as fast as the binary search of course because you have to take time to build the hashset, but its not bad, and if you need to keep the list and do a lot of future searching it might be the best option. Also, I know javascript objects arent really just hashsets, its complicated, but it mostly works pretty well.
Honestly though, for 3000 items I wouldnt change the code. Thats still not big enough to be an issue. That will run in like 30ms. So it also depends on how often its going to run. Once an hour? Forget about it. Once per millisecond? Definitely gotta optimize that.
if we are talking about the algorithm to find common elements between two array, then here is my opinion.
function common(arr1, arr2) {
var newArr = [];
newArr = arr1.filter(function(v){ return arr2.indexOf(v) >= 0;})
newArr.concat(arr2.filter(function(v){ return newArr.indexOf(v) >= 0;}));
return newArr;
}
but if you are going to think on performance also, then you should try another ways also.
first check the performance for javascript loop here, it will help you to figure out best way
https://dzone.com/articles/performance-check-on-different-type-of-for-loops-a
https://hackernoon.com/javascript-performance-test-for-vs-for-each-vs-map-reduce-filter-find-32c1113f19d7

Loop not looping inside array & comparing elements of an array

In this function I am trying loop into an array, and then return the following thing: if the year is formed by all different digits, then it's a happy year and should be stored where it belongs, in the happy array. If not, it should go in the notHappy array.
Now the problems:
1) The IF condition I tried returns nothing, []. I am quite sure it's not the right way of doing it.
for (var i = 0; i <= t.length; i++) {
if (i[0] != i[1] && i[0] != i[2] && i[0] != i[3]) {
o.happy.push(i++);
} else {
o.notHappy.push(i++)
}
}
2) I tried the same loop with a simple i%2 === 0 condition and I found out that the loop ignores my arr altogether and returns [0, 2, 4] instead of the actual numbers. It's like it would start looping from 0 itself. How come?
function nextHappyYear(arr){
var o = {
happy: [],
notHappy: []
};
var t = arr.map(e => e.toString().split(""));
for (var i = 0; i <= t.length; i++) {
if (i%2 === 0) {
o.happy.push(i++);
} else { o.notHappy.push(i++)}
}
return console.log(o.happy)
}
nextHappyYear([1021, 1022, 1023, 1024]) // returns [0, 2, 4] instead of [1022, 1024]
Your code has some issues
1-for (var i = 0; i <= t.length; i++)
Arrays indexes start from 0 and ends with length - 1. So your condition i <= t.length makes an error. Change it to i < t.length.
2-if (i%2 === 0)
This is not your question condition. You must get all digits in a year and check equality of them.
3-o.happy.push(i++);
This part have 2 problem. First, you push into happy array the index of that year, not the year. Second, i++ increase i by one and one year will get skipped!
4-if (i[0] != i[1] && i[0] != i[2] && i[0] != i[3])
You check just the first digit with others and you don't check second with third and fourth, third digit with forth also.
Try this
function hasDuplicate(arr) {
arr.sort()
for (var i = 0; i < arr.length - 1; i++) {
if (arr[i + 1] == arr[i]) {
return true;
}
}
return false;
}
function happyYear1(arr) {
var o = {
happy: [],
notHappy: []
};
for (var i = 0; i < arr.length; i++) {
if (!hasDuplicate((arr[i] + '').split(""))) {
o.happy.push(arr[i]);
} else {
o.notHappy.push(arr[i]);
}
}
return o;
}
var output = happyYear1([1021, 1022, 1023, 1024]); // returns [0, 2, 4] instead of [1022, 1024]
console.log(output);

How to programmatically create 3D array that increments to a defined number, resets to zero, and increments again?

Starting with this initial 2D array:
var initialArray = [[2,3],[6,7],[4,5],[1,2],[5,6],[2,3]];
I need to create this 3D array programmatically:
var fullArray = [
[[2,3],[6,7],[4,5],[1,2],[5,6],[2,3]],
[[3,4],[0,1],[5,6],[2,3],[6,7],[3,4]],
[[4,5],[1,2],[6,7],[3,4],[0,1],[4,5]],
[[5,6],[2,3],[0,1],[4,5],[1,2],[5,6]],
[[6,7],[3,4],[1,2],[5,6],[2,3],[6,7]],
[[0,1],[4,5],[2,3],[6,7],[3,4],[0,1]],
[[1,2],[5,6],[3,4],[0,1],[4,5],[1,2]],
[[2,3],[6,7],[4,5],[1,2],[5,6],[2,3]],
[[3,4],[0,1],[5,6],[2,3],[6,7],[3,4]],
[[4,5],[1,2],[6,7],[3,4],[0,1],[4,5]],
[[5,6],[2,3],[0,1],[4,5],[1,2],[5,6]]
];
See the pattern?
On each pair, the [0] position should increment to 6 (from any starting number <= 6) and then reset to 0 and then continue incrementing. Similarly, the [1] position should increment to 7 (from any starting number <= 7) and then reset to 1 and then continue incrementing.
In this example, there are 10 2D arrays contained in the fullArray. However, I need this number to be a variable. Something like this:
var numberOf2DArraysInFullArray = 12;
Furthermore, the initial array should be flexible so that initialArray values can be rearranged like this (but with the same iteration follow-through rules stated above):
var initialArray = [[6,7],[2,3],[5,6],[4,5],[1,2],[6,7]];
Any thoughts on how to programmatically create this structure?
Stumped on how to gracefully pull this off.
Feedback greatly appreciated!
Here's a solution, I've separated the methods, and I made it so if instead of pairs it's an N size array and you want the [2] to increase up to 8 and reset to 2, if that's not needed you can simplify the of the loop for(var j = 0; j < innerArray.length; j++)
var initialArray = [[2,3],[6,7],[4,5],[1,2],[5,6],[2,3]];
var create3DArray = function(array, size){
var newArray = [initialArray];
for(var i = 0; i < size; i++)
{
newArray.push(getNextArrayRow(newArray[i]));
}
return newArray;
}
var getNextArrayRow = function(array){
var nextRow = [];
for(var i = 0; i < array.length; i++)
{
var innerArray = array[i];
var nextElement = [];
for(var j = 0; j < innerArray.length; j++)
{
var value = (innerArray[j] + 1) % (7 + j);
value = value === 0 ? j : value;
nextElement.push(value);
}
nextRow.push(nextElement);
}
return nextRow;
}
console.log(create3DArray(initialArray,3));
Note, the results from running the snippet are a bit difficult to read...
var initialArray = [[2,3],[6,7],[4,5],[1,2],[5,6],[2,3]];
var numOfArrays = 10;
// get a range array [0, 1, 2, ...]
var range = [];
for (var i = 0; i < numOfArrays; i++) {
range.push(i);
}
var result = range.reduce(function(prev, index) {
if (index == 0) {
return prev;
}
prev.push(transformArray(prev[index - 1]));
return prev;
}, [initialArray])
console.log(result);
function transformArray(arr) {
return arr.map(transformSubArray)
}
function transformSubArray(arr) {
return arr.map(function(val) {
return val == 7 ? 0 : val + 1;
})
}
Here's a pretty simple functional-ish implementation

Categories

Resources