using lodash unique on an array of arrays - javascript

I am not sure how to use this to remove duplicate arrays from the main array. so consider the following:
var arr = [
[0, 1],
[0, 1],
[2, 1],
];
The resulting array should look like:
var arr = [
[0, 1],
[2, 1],
];
The documentation makes sense for a single array of elements but not a 2d array.
Ideas?
Update, One small issue with some solutions:
The array to be turned unique might have:
var arr = [
[0, 1]
[0, 2]
[0, 3]
[0, 1]
[2, 1]
]
the array in side the array should have all value compared, so in the above example, it should spit out:
var arr = [
[0, 1]
[0, 2]
[0, 3]
[2, 1]
]
The duplicate being [0, 1]

The easiest way would probably be to use uniq method and then convert the inner arrays to some string representation, JSON.stringify should be good enough solution.
var arr = [[0, 1], [0, 2], [0, 3], [0, 1], [2, 1]]
_.uniq(arr, function(item) {
return JSON.stringify(item);
});
// [[0,1], [0,2], [0,3], [2,1]]

You would use the .uniq function in lodash:
var arr = [
[0, 1],
[0, 1],
[2, 1],
]
var uniqueList = _.uniq(arr, function(item, key, a) {
return item.a;
});
The resulting array will look like:
//var arr = [Object: [0, 1], Object: [2, 1]];

Sure, casting to JSON works, but it feels like we might be wasting resources. I'm using the following Lodash-code in Node.js:
const _ = require("lodash");
var arr = [
[0, 1],
[0, 1],
[2, 1],
];
var uni = _.uniqWith(arr, _.isEqual);
console.log(uni);
Works like a charm, check the Repl here. More on uniqWith at the Lodash docs.

It doesn't use lodash, not optimized I agree :
//remove duplicate array of array of arrays
Array.prototype.uniqueArray = function() {
var uniqObj = {};
this.forEach(function (item) {
uniqObj[JSON.stringify(item)] = 1;
});
var uniqArray = [];
for(var key in uniqObj) {
if (uniqObj.hasOwnProperty(key)) {
uniqArray.push(JSON.parse(key))
}
}
return uniqArray;
};

Related

combining "columns" in multiple arrays

I have an array of arrays:
var arr = [
[0, 3, 3],
[0, 4, 3],
[1, 3, 4],
[1, 4, 4]
];
I want to create a new array that combines the contents of each index of the inner arrays. For example, the first elements at index 0 of each of the inner arrays are 0, 0, 1, and 1. I want to create a new array that combines those elements so that I end up with [0, 1] (I don't want duplicates in the new array). The next "column" is 3, 4, 3, and 4. So I'd want an array of [3, 4].
The end result I want is
[
[0, 1],
[3, 4],
[3, 4]
]
I can't quite figure out how to do this.
May not be the most efficient, but does meet you cryptic requirements.
var arr = [
[0, 3, 3],
[0, 4, 3],
[1, 3, 4],
[1, 4, 4]
];
const unique = (myArray) => [...new Set(myArray)];
let x, y,
tarr = [], // temp array
farr = []; // final array
for (x=0; x<arr.length; x++) {
tarr.length = 0;
for (y=0; y<arr[x].length; y++) {
tarr.push(arr[y][x])
}
farr.push( unique(tarr) );
}
console.log(farr.join('\n'));
Here another solution.
const result = (arr) => {
let index = 0;
const min = Math.min(...arr.map(r => r.length)) // get min length
const grid = [];
while (index < min) { // loop with min
let s = new Set(); // using set to keep unique values
arr.forEach(r => s.add(r[index])); // pick value
grid.push([...s]); // get array from set
index++;
}
return grid
}
const array = [ [0, 3, 3], [0, 4, 3], [1, 3, 4], [1, 4, 4] ];
console.log(result(array))

How do I match pairs in a 2 dimensional array in JavaScript?

I have an array with pairs of numbers and need to find matching pairs within the array
numberStore = [ [0,0],[1,1],[1,2],[1,3],[1,4],[1,5]... ]
I want to be able to find 1,4. Is there a way to find this array without relying on numberStore[4]?
Since you need to perform this search frequently, I would build a hashed set to avoid mapping and searching over and over. For example
const numberStore = [ [0,0],[1,1],[1,2],[1,3],[1,4],[1,5] ]
const hashedSet = new Set(numberStore.map(pair => pair.toString()))
// looks like ["0,0", "1,1", "1,2", "1,3", etc]
console.log([...hashedSet])
const search = (find) => {
return hashedSet.has(find.toString())
}
console.info('Find [1,4]', search([1,4]))
console.info('Find [4,1]', search([4,1]))
I've used Array.prototype.toString() as the hashing function but you could substitute anything there that creates a unique and comparable entity for each pair.
Use Array.prototype.find():
var numberStore = [
[0, 0],
[1, 1],
[1, 2],
[1, 3],
[1, 4],
[1, 5]
];
var oneFour = numberStore.find(function([a, b]) {
return a == 1 && b == 4;
});
console.log(oneFour);
Or if you prefer ES6 arrow syntax:
var numberStore = [
[0, 0],
[1, 1],
[1, 2],
[1, 3],
[1, 4],
[1, 5]
];
var oneFour = numberStore.find(([a, b]) => a == 1 && b == 4);
console.log(oneFour);
Another alternative is using the method some() to test elements for a condition.
var numberStore = [
[0,0],
[1,1],
[1,2],
[1,3],
[1,4],
[1,5]
];
var exists = numberStore.some(([a, b]) => a === 1 && b === 4);
console.log(exists ? "Pair [1,4] exists" : "Pair [1,4] don't exists");

array index selection like in numpy but in javascript

I have a 3x3 array:
var my_array = [[0,1,2],
[3,4,5],
[6,7,8]];
and want to get the first 2x2 block of it (or any other 2x2 block):
[[0,1],
[3,4]]
with numpy I would have written:
my_array = np.arange(9).reshape((3,3))
my_array[:2, :2]
to get the correct result.
I tried in javascript:
my_array.slice(0, 2).slice(0, 2);
but the second slice affects the first dimension, doing nothing.
Am I doomed to use for loop or is there some new ES6 syntax that would make my life simpler?
Could use a combination of Array.slice and Array.map:
const input = [
[0, 1, 2],
[3, 4, 5],
[6, 7, 8]
];
const result = input.slice(0, 2).map(arr => arr.slice(0, 2));
console.log(result);
You can use .map() and .slice() methods:
var my_array = [[0,1,2],
[3,4,5],
[6,7,8]];
var result = my_array.slice(0, 2).map(a => a.slice(0, 2));
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
You could take objects for the indices and for the length of the wanted sub arrays.. Then slice and map the sliced sub arrays.
var array = [[0, 1, 2], [3, 4, 5], [6, 7, 8]],
length = { x: 2, y: 2 },
indices = { i: 0, j: 0 },
result = array.slice(indices.i, indices.i + length.x).map(a => a.slice(indices.j, indices.j + length.y));
console.log(result);
It dont seems to a 3x# array , it is just array of arrays.
You can first use slice to get an array of only first two elements that is
[[0, 1, 2],[3, 4, 5]]
then use reduce to return a new array & inside it get only the first two values
var my_array = [
[0, 1, 2],
[3, 4, 5],
[6, 7, 8]
];
let x = my_array.slice(0, 2).reduce(function(acc, curr) {
acc.push(curr.slice(0, 2))
return acc;
}, [])
console.log(x)
const input = [
[0, 1, 2],
[3, 4, 5],
[6, 7, 8]
];
let result =[]
input.forEach(([a, b], index) => {if(index < 2) result.push([a, b])})
console.log(result);
If you are going to work a lot with matrices, then you should check out math.js.
Try the following:
var my_array = [[0,1,2],
[3,4,5],
[6,7,8]];
var matrix = math.matrix(my_array);
var subset = matrix.subset(math.index([0, 1], [0, 1]));
Working example.

Fastest way to Reduce and concat (or deep flatten) arrays of arrays

As input, I receive two types of arrays of arrays made of x and y coordinates that represent polygon and multipolygon geometries.
array1 represents coordinates of a simple polygon geometry and array2 represent a multipolygon geometry:
var array1 = [[[0 , 0], [0, 1], [0 ,2]]]
var array2 = [[[[0, 0] , [0, 1], [0, 2]], [[1, 0], [1, 1], [1 ,2]]]]
Multipolygon geometry (array2) are represented by an array of arrays one level deeper than simple polygon geometry (array1).
I want to flatten those arrays in order to get those output:
if input is array1 type : array1_out = [[0, 0, 0, 1, 0, 2]]
if input is array2 type : array2_out = [[0, 0, 0, 1, 0, 2], [1, 0, 1, 1, 1, 2]]
My function is the following:
for (i=0; i < array_input.length; i++){
var array_concat = array_input[i].reduce(function(a, b){
return a.concat(b);
});
}
With this function above, the output for array1 is correct but the output of array2 is the following:
[[[0, 0] ,[0, 1], [0, 2]], [1, 0], [1, 1], [1, 2]]]
Is there a function to deeply flatten those two types of arrays?
Edit: Performance really matter here as the arrays are really big
You can find a lot of helpful tools for manipulating arrays and collections in the Underscore and lodash libraries.
var arrays1 = [[[0 , 0], [0, 1], [0 ,2]]];
var array2 = [[[[0, 0] , [0, 1], [0, 2]], [[1, 0], [1, 1], [1 ,2]], ]];
var array1_out = flattenSimple(arrays1);
console.log(JSON.stringify(array1_out));
var array2_out = flattenMultiple(array2);
console.log(JSON.stringify(array2_out));
function flattenSimple(array_input) {
return _.flatten(array_input);
}
function flattenMultiple(array_input) {
array_input = array_input[0];
return array_input.map(function(a) {
return _.flatten(a);
});
}
Will produce the output you're looking for. I broke it into a flatten fn for each type, but you could use the same fn with a flag or more complex logic to know which type you're working with.
Fiddle
You can add a small wrapper for your function, that can check what type in input and a bit modify input
function getDeepLength(arr) {
for (var i = 0, cur = arr; cur[0] instanceof Array; i++, cur = cur[0]);
return i;
}
function Flatten(array_input) {
var array_concat = [];
for (i = 0; i < array_input.length; i++) {
array_concat.push(array_input[i].reduce(function(a, b) {
return a.concat(b);
}));
}
return array_concat;
}
function Wrapper(arr) {
var deep = getDeepLength(arr);
var cur = arr;
if (deep > 2) {
for (var i = deep - 2; i > 0; i--, cur = cur[0]);
}
return Flatten(cur)
}
var array1 = [
[
[0, 0],
[0, 1],
[0, 2]
]
];
var array2 = [
[
[
[0, 0],
[0, 1],
[0, 2]
],
[
[1, 0],
[1, 1],
[1, 2]
]
]
];
document.getElementById('r').innerHTML = "array1: "
+ JSON.stringify(array1)+"<br/>"
+ "flat array1: "+JSON.stringify(Wrapper(array1))+"<br/>"
+ "array2: "+JSON.stringify(array2)+"<br/>"
+ "flat array2: "+JSON.stringify(Wrapper(array2));
<div id='r'></div>

How to convert a 2D array to a tree (of objects) in JavaScript?

I have a 2D array representing a tree in this format:
[["Food", 0], ["Dairy", 1], ["Milk", 2], ["Low-fat", 3], ["Butter", 2], ["Cheese", 2], ["Vegetables", 1], ["Spinach", 2], ["Meat", 1], ["Fish", 2], ["Salmon", 3], ["Poultry", 2]]
Each item (node) is an array where its first element is the name, and the second is the level (depth) of the node.
I need to convert this 2D array to nested JavaScript objects, where each node-object consists of name (string) and children (array of objects). The result should be the root object (here, "Food") with all other items as its children. The input array will always come ordered, so it can be assumed that the first element is root.
What's the best way to go about this, either with iteration or recursion?
Recursion isn't necessary. I think something like this is what you're looking for:
function tree_from_list(list) {
var list_node = list.shift();
var depth = list_node[1];
var root = {name: list_node[0], children: []};
var tree_node;
var cur_nodes = [];
cur_nodes[depth] = root;
while (list.length > 0) {
list_node = list.shift();
tree_node = {name: list_node[0], children: []};
depth = list_node[1];
if (cur_nodes[depth - 1] === undefined)
throw 'invalid list!';
cur_nodes[depth - 1].children.push(tree_node);
cur_nodes[depth] = tree_node;
}
return root;
}
var list = [["Food", 0], ["Dairy", 1], ["Milk", 2], ["Low-fat", 3], ["Butter", 2], ["Cheese", 2], ["Vegetables", 1], ["Spinach", 2], ["Meat", 1], ["Fish", 2], ["Salmon", 3], ["Poultry", 2]];
var tree = tree_from_list(list);
Here's a mostly pointless (and less efficient) recursive solution:
function mktree(lis, lvl) {
var i, el, c, itemlis = [];
for (i = 0; el = lis[i++];) {
if (lvl !== el[1])
break;
var item = {};
[item[el[0]], c] = mktree(lis.slice(i), lvl + 1);
i += c - 1; // skip ahead
itemlis.push(item);
}
return [itemlis, i];
}
function lis_to_tree(arr) {
return mktree(arr, 0, 0)[0][0];
}
var arr = [["Food", 0], ["Dairy", 1], ["Milk", 2], ["Low-fat", 3], ["2%", 3],
["Butter", 2], ["Cheese", 2], ["Vegetables", 1], ["Spinach", 2],
["Meat", 1], ["Fish", 2], ["Salmon", 3], ["Poultry", 2]];
var tree = lis_to_tree(arr);
(Note that this relies on destructuring assignment to skip elements that have already been processed. You could remove this feature, but it would be much slower.)
I call this mostly pointless because it's essentially trying to imitate iteration in the way it maintains a count of elements that it's already processed, so that it can skip ahead in the list. I don't say it's completely useless because I still find the recursive version easier to read than its iterative counterpart.

Categories