Basiclly what i am trying to do is for sort the values of a array input like uniteUnique([1, 3, 2], [5, 2, 1, 4], [2, 1]) into a sorted 2D array like [[1, 1, 1], [2, 2, 2], [4], [3], [5]]. The arrays don't have to be in number/ value order. The code below is what i tried:
function uniteUnique(arr) {
let times = 0;
var unique = [[]];
for (var i = 0; i < Array.prototype.slice.call(arguments).length; i++) {
times = 0;
for (var j = 0; j < arguments[i].length; j++) {
for (var h = 0; h < unique.length; h++) {
var pushArray = []
if(unique[h][0] === arguments[i][j]) {
unique[h].push(arguments[i][j])
arguments[i].splice(j)
}
else {
unique.push([arguments[i][j]])
}
}
}
}
return unique
}
uniteUnique([1, 3, 2], [5, 2, 1, 4], [2, 1]);
--> https://repl.it/#John_Nicole/unique
I only have one parameter for all of the input arrays
I have a uniquearray with 1 blank array. Its a 2D array.
Then i go through, for instance, the values of [1, 3, 2] and check if any arrays in uniquehave there first value as my number (arguments[i][j]).
If true, i push the number arguments[i][j], then remove the number in the original array with splice() .
If false, i push new array into unique with this unrecognized value.
Quick Overview of the variables
h: This is the array in unique that i am going to compare with. It could be [2, 2, 2].
i: This is the array from the input. For instance, [1, 3, 2].
j: This the number itself, its partner with i. For example, arguments[i][j] = [2, 1] --> 2
arguments grabs all, in this case, the 3 input arrays.
Times: This just means 0. No use what so ever.
The input could include 2D arrays in themselves like [1, 3, 2], [1, [5]], [2, [4]]
This is a part of a freeCodeCamp challenge --> https://www.freecodecamp.org/challenges/sorted-union
My question is that, why is my output:
[ [],
[ 1, 1 ],
[ 5, 5 ],
[ 5 ],
[ undefined, undefined ],
[ 2, 2 ],
[ 2 ],
[ 2 ],
[ 2 ],
[ 2 ],
[ undefined, undefined ],
[ undefined, undefined ],
[ undefined, undefined ],
[ undefined, undefined ] ]
?
when the wanted output is: Wanted output was [1, 1, 1], [2, 2, 2], [4], [3], [5]
Am i doing something wrong?
I'm getting multiple 2's arrays for example ([[ 2 ],[ 2 ],[ 2 ],[ 2 ]]) even though i'm suppose to be putting all 2 into one array?
You could use a hash table and check if the hash key exists and if not, then take an empty array as value for the hash and push it to the result set.
The hash table is an object (here without prototypes) which takes the values as keys and an array as value. A the the end the hash table keeps all values in arrays, which are inserted in the result set if a new value is found.
{
1: [1, 1, 1],
2: [2, 2, 2],
3: [3],
4: [4],
5: [5]
}
function uniteUnique() {
var result = [],
hash = Object.create(null);
Array.prototype.forEach.call(arguments, function (a) {
a.forEach(function (b) {
if (!(b in hash)) {
hash[b] = [];
result.push(hash[b]);
}
hash[b].push(b);
});
});
return result;
}
console.log(uniteUnique([1, 3, 2], [5, 2, 1, 4], [2, 1]));
.as-console-wrapper { max-height: 100% !important; top: 0; }
Some annotation to your code (not used variables are deleted):
function uniteUnique() {
var unique = [], // move all declarations to top
i, j, h,
pushed;
// array like objects have a length property
for (i = 0; i < arguments.length; i++) {
for (j = 0; j < arguments[i].length; j++) {
pushed = false;
for (h = 0; h < unique.length; h++) {
if (unique[h][0] === arguments[i][j]) {
// take the element, do not use splice, because with splicing
// the array becomes shorter and the index is updated in the
// next loop and is pointing to the element with the wrong index,
// because you get the element after next
// it is better not to mutate a variable, if it works without
// in this case, you iterate and visit each element only once
unique[h].push(arguments[i][j]);
pushed = true; // a value is found
break; // exit this loop
} // prevent more looping
}
if (!pushed) { // if not found
unique.push([arguments[i][j]]); // push the value
}
}
}
return unique;
}
console.log(uniteUnique([1, 3, 2], [5, 2, 1, 4], [2, 1]));
.as-console-wrapper { max-height: 100% !important; top: 0; }
Related
Let's say I have 4 arrays:
var arrays = [
[1, 2, 1],
[1, 3, 4],
[1, 2, 3],
[0, 2, 2]
];
And I want to return the child/sub arrays that start with both 1 and 2, what type of loop would I need?
Currently, this is what I have:
var arrays = [
[1, 2, 1],
[1, 3, 4],
[1, 2, 3],
[0, 2, 2]
];
var selected = [1, 2]; // These are the values that need to match
var result = [];
for (var i = 0; i < selected.length; i++) {
for (var j = 0; j < arrays.length; j++) {
if (arrays[i][j] === selected[i]) {
result.push(arrays[i]);
}
}
}
When there's more than 1 value in the selected array, it seems to return all the ones that match 2 on the second index, so the result would be:
[
[1, 2, 1],
[1, 2, 3],
[0, 2, 2]
]
The loop needs to ensure that on the second iteration it's making sure the first value is still true, as my intended result would be:
[
[1, 2, 1],
[1, 2, 3]
]
Please someone help me, I've had my head trying hundreds of different loop and checks variations for 2-3 days.
Thanks so much!!
Jake
Your current code pushes to the result array whenever any given index matches between arrays and selected. Instead you will need to reverse your loops and iterate over selected for every sub array and check if every element matches, if not break the inner loop and don't push.
const arrays = [
[1, 2, 1],
[1, 3, 4],
[1, 2, 3],
[0, 2, 2],
];
const selected = [1, 2]; // These are the values that need to match
const result = [];
for (let i = 0; i < arrays.length; i++) {
let match = true;
for (let j = 0; j < selected.length; j++) {
if (arrays[i][j] !== selected[j]) {
match = false;
break;
}
}
if (match) {
result.push(arrays[i]);
}
}
console.log(result);
A more modern solution would be to use filter() with a nested every() call on selected.
const arrays = [
[1, 2, 1],
[1, 3, 4],
[1, 2, 3],
[0, 2, 2],
];
var selected = [1, 2];
const result = arrays.filter(arr => selected.every((n, i) => n === arr[i]));
console.log(result);
Here is another approach where you turn both arrays to string and check it those inner arrays start with selected array.
var arrays = [
[1, 2, 1],
[1, 3, 4],
[1, 2, 3],
[0, 2, 2]
];
var selected = [1, 2];
const result = arrays.filter(e => e.toString().startsWith(selected.toString()))
console.log(result)
Let's try to put your condition into words. That way, an implementation may come to mind more easily.
A short wording may be: "Take all arrays that match (rather: start with) a certain sub-array." In code, it may look like this:
const arrays = [
[1, 2, 1],
[1, 3, 4],
[1, 2, 3],
[0, 2, 2]
];
const selection = [1, 2];
const result = filterArrays(arrays, selection);
console.log(result);
function filterArrays(arrays, selection) {
const selectedArrays = [];
for (let i = 0; i < arrays.length; ++i) {
const array = arrays[i];
const subarray = array.slice(0, selection.length); // Get starting sub-array
if (compareArrays(subarray, selection)) {
selectedArrays.push(array);
}
}
return selectedArrays;
}
/*Ignore; helper function*/
function compareArrays(array1, array2) {
if (array1.length !== array2.length) return false;
const length = array1.length;
for (let i = 0; i < length; ++i) {
if (array1[i] !== array2[i]) return false;
}
return true;
}
.as-console-wrapper {max-height:100%!important}
Another, more specific wording may be: "Take all arrays that match a selection at an index." Note that we only reworded the "match a sub-array" part. I believe this is what you tried.
Refer to pilchard's answer for an implementation. Note that their implementation assumes the arrays in arrays to be at least the same length as selected.
I see you used var instead of the preferred modern let/const declarators. Here's a short outline of their differences:
let/const declarators:
Block-scoped.
Narrower scope means less name-space pollution.
More similar to declarators in other well-known languages:
Variables of these declarators cannot be used before their declaration (see TDZ).
var declarator:
Function-scoped.
Hoisted and with no TDZ, resulting in this (perhaps confusing) behaviour:
Variables declared with var can be used even before their declaration.
Duplicate declarations are allowed since they are effectively the same.
Also, JavaScript has different kinds of for-loops:
for-loop: The for-loops you used are this kind. It is the most versatile kind.
for...of-loop: A loop to iterate over an iterable object (see iterators). For example, arrays are iterable, so you can get its values with a for...of-loop:
const values = [1, 2, 3];
let sum = 0;
for (const value of array) {
sum += value;
}
console.log(sum); // -> 6
for...in-loop: A loop to iterate over enumerable properties of an object. It is easily confused with a for...of-loop, but MDN's example demonstrates the differences understandably.
In my code example above, the for-loop in filterArrays() can be replaced with a for...of-loop to better convey my intention: To iterate over all arrays in arrays, disregarding their index:
for (let i = 0; i < arrays.length; ++i) {
const array = arrays[i];
// ...
}
// Same as
for (const array of arrays) {
// ...
}
I know there are a couple of answers on the matter, but as I was trying to make my own, I got very lost on how recursive functions work, here's what I tried :
function flatcoords(arr) {
for (i = 0; i < arr.length; i++) {
const value = arr[i];
if (value.isArray) {
return flatcoords(value);
} else {
return arr;
}
}
}
const arr_test = [
[
[1, 2],
[1, 2]
],
[1, 2],
[1, 2],
[
[
[1, 2],
[1, 2]
]
]
];
//wanted_result = [ [1,2],[1,2],[1,2],[1,2],[1,2],[1,2] ]
console.log(flatcoords(arr_test));
I want the result to be a 2D array, what am I missing in my logic?
First of all, you need to declare all variables before use. Then you could use Array.isArray for a check if an item is an array.
In this case, I suggest to check the first item of the checked element if it is an array as well, in this case flat the array.
As result, an array comes in handy, because not only one element should be returned, but all. And while arrays have more item, you need to append all items to the existing result array.
function flatcoords(array) {
var result = [],
value,
i;
for (i = 0; i < array.length; i++) {
value = array[i];
if (Array.isArray(value) && Array.isArray(value[0])) {
result = result.concat(flatcoords(value));
} else {
result.push(value);
}
}
return result;
}
const arr_test = [[[1, 2], [1, 2]], [1, 2], [1, 2], [[[1, 2], [1, 2]]]];
console.log(flatcoords(arr_test));
.as-console-wrapper { max-height: 100% !important; top: 0; }
I would like to compare multiple array and finally have an array that contain all unique values from different array. I tried to:
1,Use the filter method to compare the difference between 2 arrays
2,Call a for loop to input the arrays into the filter method
and the code is as follows
function diffArray(arr1, arr2) {
function filterfunction (arr1, arr2) {
return arr1.filter(function(item) {
return arr2.indexOf(item) === -1;
});
}
return filterfunction (arr1,arr2).concat(filterfunction(arr2,arr1));
}
function extractArray() {
var args = Array.prototype.slice.call(arguments);
for (var i =0; i < args.length; i++) {
diffArray(args[i],args[i+1]);
}
}
extractArray([3, 3, 3, 2, 5], [2, 1, 5, 7], [3, 4, 6, 6], [1, 2, 3]);
However it does not work and return the error message "Cannot read property 'indexOf' of underfined" .... What's wrong with the logic and what should I change to make it works?
Many thanks for your help in advance!
Re: For all that mark this issue as duplicated ... what I am looking for, is a solution that can let me to put as many arrays as I want for input and reduce all the difference (e.g input 10000 arrays and return 1 array for unique value), but not only comparing 2 arrays .. The solutions that I have seen are always with 2 arrays only.
I don't use filters or anything of the sort but it will get the job done. I first create an empty array and concat the next array to it. Then I pass it to delete the duplicates and return the newly "filtered" array back for use.
function deleteDuplicates(a){
for(var i = a.length - 1; i >= 0; i--){
if(a.indexOf(a[i]) !== i){
a.splice(i, 1);
}
}
return a;
}
function extractArray() {
var args = Array.prototype.slice.call(arguments), arr = [];
for (var i = 0; i < args.length; i++) {
arr = deleteDuplicates(arr.concat(args[i]));
}
return arr;
}
var arr = extractArray([3, 3, 3, 2, 5], [2, 1, 5, 7], [3, 4, 6, 6], [1, 2, 3]);
console.log(arr) //[3, 2, 5, 1, 7, 4, 6]
I have this multi-dimensional array.
var multiArray = [
['steak tips', 'burgers'],
['ice cream', 'cake', 'cookies'],
['corona', 'jack daniels']
]
I am looking for a function that can somehow calculate the total amount of possible combinations for the following use case:
Print one word from the first nested array, one word from the second nested array, and one word from the third nested array.
I am simply hoping to end up with just an integer result that tells me how many possible solutions there are. It does NOT have to actually go about printing all of these possible combinations to the screen, or anything like that.
This simple problem which basically asks for the product of the lengths of an arbitrary number of arrays has an elegant generic solution using the Array.reduce method:
function numCombinations(...arrays) {
return arrays.reduce((prod, array) => prod * array.length, 1);
}
// Examples:
console.log(numCombinations([1, 2], [3, 4, 5], [6])); // 6
console.log(numCombinations([1, 2])); // 2
console.log(numCombinations([1], [])); // 0
We need to specify an initial value of 1 which is the identity element of multiplication.
Appendix: Alternative, exemplary solutions:
// Expects three arrays, returns the product of their lengths:
function numCombinations1(array1, array2, array3) {
return array1.length * array2.length * array3.length;
}
console.log(numCombinations1([1, 2], [3, 4, 5], [6])); // 6
// Expects one array containing the three arrays:
function numCombinations2(arrays) {
return arrays[0].length * arrays[1].length * arrays[2].length;
}
console.log(numCombinations2([[1, 2], [3, 4, 5], [6]])); // 6
// Expects one array containing a variable number of arrays:
function numCombinations3(arrays) {
var product = 1;
for (var i = 0; i < arrays.length; i++) {
product = product * arrays[i].length;
}
return product;
}
console.log(numCombinations3([[1, 2], [3, 4, 5], [6]])); // 6
// Replaced traditional for-loop with simpler for-of loop:
function numCombinations4(arrays) {
var product = 1;
for (var array of arrays) {
product *= array.length;
}
return product;
}
console.log(numCombinations4([[1, 2], [3, 4, 5], [6]])); // 6
// Expects a variable number of array arguments using rest parasmeter syntax (...):
function numCombinations5(...arrays) {
var product = 1;
for (var array of arrays) {
product *= array.length;
}
return product;
}
console.log(numCombinations5([1, 2], [3, 4, 5], [6])); // 6
// Replaced for-of loop with Array.reduce:
function numCombinations6(...arrays) {
return arrays.reduce(function (product, array) {
return product * array.length;
}, 1);
}
console.log(numCombinations6([1, 2], [3, 4, 5], [6])); // 6
// Replaced Array.reduce callback function with shorter arrow function:
function numCombinations7(...arrays) {
return arrays.reduce((product, array) => product * array.length, 1);
}
console.log(numCombinations7([1, 2], [3, 4, 5], [6])); // 6
I have the following array:
var array = [
[1, 2, 3, 4, 5],
[2, 3],
[3, 4],
[3]
];
I'm trying to end up with a unique set of numbers from the arrays that appear in all arrays.
Therefore in this case returning
[3]
Any suggestions?
Many thanks :)
Store the value of array[0] in a variable (let's call it result).
Loop from array[1] to the end.
In this loop, run through all the values of result. If the current value of result is not in array[x] remove this value from result.
At the end of the loop, result only contains the desired values.
Aside from the obvious "iterate over every array and find matching numbers in every other array" you could flatten (concat) the original array, sort it, then look for numbers that occur at four consecutive indexes. I'm not a fan of questions where OP doesn't show any effort, but this was quite fun, so here it goes
array.reduce(function(prev, cur){
return prev.concat(cur);
})
.sort()
.filter(function(item, i, arr){
return arr[ i + array.length - 1 ] === item;
});
Or ES2015:
array.reduce((prev, cur)=>prev.concat(cur))
.sort()
.filter((i, idx, arr)=>(arr[idx+array.length-1]===i));
After learning i was using the wrong javascript method to remove from an array (pop) and some more tinkering. I got it working many thanks for those who responded.
var array = [
[2, 3, 5, 1],
[3, 4, 2, 1],
[3, 2],
[3, 4, 2, 5]
];
var result = array[0]
for (var i = 1; i < array.length; i++) {
for (var j = 0; j < result.length; j++) {
var arrayQuery = $.inArray(result[j], array[i]);
if(arrayQuery == -1){
result.splice(j, 1)
}
};
};
Try this:
var array = [
[1, 2, 3, 4, 5],
[2, 3],
[3, 4],
[3]
];
var arr = [];
for(var x in array){
for(var y in array[x]){
if(arr.indexOf(array[x][y]) === -1){
arr.push(array[x][y]);
}
}
}
console.log(arr);
Output:
[1, 2, 3, 4, 5]
Working Demo