use lodash javascript to full join two-dimensional array - javascript

I have two two-dimensional array.
var arr1=[[1,20],[2,30]];
var arr2=[[2,40],[3,50]];
This is expected output:
[[1,20,null],[2,30,40],[3,null,50]]
It is like full join of two data frames. The logic is similar to this pseudo code:
df1.join(df2, df1[col_1] == df2[col_1], 'full')
but this case is for two-dimensional array. Can lodash do this? If not, how to do it in vanilla javascript?

Well, lodash can't do this, but we can:
function flatten2d(arr1, arr2) {
const o1 = _.fromPairs(arr1);
const o2 = _.fromPairs(arr2);
const result = [];
_.forEach(o1, (v, k) => {
const v2 = o2[k] || null;
result.push([k|0, v, v2]);
delete o2[k];
});
// at this point, only items non-existing
// in o1 are left in o2
_.forEach(o2, (v, k) => {
result.push([k|0, null, v]);
});
return result;
}
Testing:
flatten2d([[1,20],[2,30]], [[2,40],[3,50]])
Result:
[[1,20,null], [2,30,40], [3,null,50]]

If you don't have duplicate id's in any single array then you can try combine them, and group them using groupBy with first element (i.e. the key 0), and if you have duplicates, anyway I am not sure what exactly output you are looking for! Here is what you can do:
_(arr1.concat(arr2)).groupBy('0').map(v=>
[v[0][0]].concat(v.length > 1 ? v.map(m=>m[1]) : [v[0][1], null])
).value();
Here is an working snippet for you:
var arr1=[[1,20],[2,30]];
var arr2=[[2,40],[3,50]];
var res = _(arr1.concat(arr2)).groupBy('0').map(v=>
[v[0][0]].concat(v.length > 1 ? v.map(m=>m[1]) : [v[0][1],null])
).value();
console.log(JSON.stringify(res));
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.4/lodash.js"></script>

Related

how to compare between two array that is inside one same array? [duplicate]

I have two arrays [a,b,c,d] and [b,d,f,h].
I want to get an array back with the common elements [b,d].
I can achieve that with a combination of filter and indexOf:
[a,b,c,d].filter(el => [b,d,f,h].indexOf(el) !== -1)
but I was wondering if and how I can do the same with reduce.
I admit that, despite looking at many examples, reduce still is to me one of the most obscure JS methods, so I'd really appreciate some advice.
ES6, a propoosal with Array#includes
The includes() method determines whether an array includes a certain element, returning true or false as appropriate.
On every loop of aa, reduce adds the element to the result array if the value is found in the test array bb. If not found, the former result is returned.
var aa = ['a','b','c','d'],
bb = ['b','d','f','h'],
cc = aa.reduce((r, a) => bb.includes(a) && r.concat(a) || r, []);
console.log(cc);
Just a smarter approach with using a single array which contains all arrays.
var aa = ['a','b','c','d'],
bb = ['b','d','f','h'],
result = [aa, bb].reduce((a, b) => a.filter(c => b.includes(c)));
console.log(result);
Reduce is designed to return a single value from a list of items. So filter makes much more sense here.
A good use for reduce would be to return the total number of common elements. Check it out here: https://jsfiddle.net/c69vgzL4/
var a = ['a','b','c','d']
var b = ['b','d','f','h']
var number_of_common = b.reduce(function(prev, next) {
return prev + (a.indexOf(next) + 1 ? 1 : 0)
}, 0)
$('body').html(number_of_common)
Not only two arrays but for an intersection of n arrays... Let's invent Array.prototype.intersect()
Array.prototype.intersect = function(...a) {
return [this,...a].reduce((p,c) => p.filter(e => c.includes(e)));
}
var arrs = [[0,2,4,6,8],[4,5,6,7],[4,6]],
arr = [0,1,2,3,4,5,6,7,8,9];
console.log(JSON.stringify(arr.intersect(...arrs)));
// or just do
console.log(JSON.stringify(["a","b","c","d"].intersect(["b","d","f","h"])));

deleting a object of an Array based on property of the object

I have an Array like this: var obj = [{x:4, y:5}, {x:6, y:2}, ...] and I'm trying to delete one of the inside objects (properties) based on the x.
this is How I'm trying to do this:
obj.forEach(function (child){
if(child.x === 4){
obj.destroy(child)
}
});
But it's not working and i get
obj.destroy is not a funtion
I also tried obj.splice(child) but it just mess up the array. so what am doing wrong here?
Also is there a better way to do this by not having to loop through all of Array property every time?
You can just use filter on the array: e.g.
let arrayToFilter = [ {x:4, y:5}, {x:6, y:2}];
const valueToFilter = 4;
var filteredArray = arrayToFilter .filter((o) => {
return o.x !== valueToFilter;
});
console.log(filteredArray);
forEach() works on array.
If obj is an array, you can simply use filter() to remove the unwanted object from the array:
var obj = [{x:4, y:5}, {x:6, y:2}]
obj = obj.filter(c => c.x !== 4)
console.log(obj);
You perhaps, have an array as obj because the one you posted in the question is simply invalid syntax.
Moreover, you can use Array#findIndex to get the index of the matching element first, and then splice that index from the array.
var obj = [{x:4, y:5}, {x:6, y:2}];
var index = obj.findIndex(item => item.x === 4);
obj.splice(index, 1);
console.log(obj);
i'm assuming your trying to filter out objects in an array which have an x that matches a given value. If thats the case, you should probably use the filter method.
So assuming thats what you mean you could do the following
obj = obj.filter(function (child){
if(child.x !== 4){
return obj
}
});
// shorter
obj = obj.filter( child => child.x !== 4 );
In this case, only the objects which do not have the value of 4 will be available to you in the obj variable. And all other objects (assuming there are no other references in your code) will be garbage collected.

JavaScript - Filter <key,value> Object by key

I am looking for a short and efficient way to filter objects by key, I have this kind of data-structure:
{"Key1":[obj1,obj2,obj3], "Key2":[obj4,obj5,obj6]}
Now I want to filter by keys, for example by "Key1":
{"Key1":[obj1,obj2,obj3]}
var object = {"Key1":[1,2,3], "Key2":[4,5,6]};
var key1 = object["Key1"];
console.log(key1);
you can use the .filter js function for filter values inside an object
var keys = {"Key1":[obj1,obj2,obj3], "Key2":[obj4,obj5,obj6]};
var objectToFind;
var keyToSearch = keys.filter(function(objects) {
return objects === objectToFind
});
The keyToSearch is an array with all the objects filter by the objectToFind variable.
Remember, in the line return objects === objectToFind is where you have to should your statement. I hope it can help you.
You can create a new object based on some custom filter criteria by using a combination of Object.keys and the array .reduce method. Note this only works in es6:
var myObject = {"Key1":["a","b","c"], "Key2":["e","f","g"]}
function filterObjectByKey(obj, filterFunc) {
return Object.keys(obj).reduce((newObj, key) => {
if (filterFunc(key)) {
newObj[key] = obj[key];
}
return newObj;
}, {});
}
const filteredObj = filterObjectByKey(myObject, x => x === "Key1")
console.log(filteredObj)
Not sure what exactly are you trying to achieve, but if you want to have a set of keys that you would like to get the data for, you have quite a few options, one is:
var keys = ['alpha', 'bravo'];
var objectToFilterOn = {
alpha: 'a',
bravo: 'b',
charlie: 'c'
};
keys.forEach(function(key) {
console.log(objectToFilterOn[key]);
});

Array intersection (set-theoretic) with Array.prototype.reduce

I have two arrays [a,b,c,d] and [b,d,f,h].
I want to get an array back with the common elements [b,d].
I can achieve that with a combination of filter and indexOf:
[a,b,c,d].filter(el => [b,d,f,h].indexOf(el) !== -1)
but I was wondering if and how I can do the same with reduce.
I admit that, despite looking at many examples, reduce still is to me one of the most obscure JS methods, so I'd really appreciate some advice.
ES6, a propoosal with Array#includes
The includes() method determines whether an array includes a certain element, returning true or false as appropriate.
On every loop of aa, reduce adds the element to the result array if the value is found in the test array bb. If not found, the former result is returned.
var aa = ['a','b','c','d'],
bb = ['b','d','f','h'],
cc = aa.reduce((r, a) => bb.includes(a) && r.concat(a) || r, []);
console.log(cc);
Just a smarter approach with using a single array which contains all arrays.
var aa = ['a','b','c','d'],
bb = ['b','d','f','h'],
result = [aa, bb].reduce((a, b) => a.filter(c => b.includes(c)));
console.log(result);
Reduce is designed to return a single value from a list of items. So filter makes much more sense here.
A good use for reduce would be to return the total number of common elements. Check it out here: https://jsfiddle.net/c69vgzL4/
var a = ['a','b','c','d']
var b = ['b','d','f','h']
var number_of_common = b.reduce(function(prev, next) {
return prev + (a.indexOf(next) + 1 ? 1 : 0)
}, 0)
$('body').html(number_of_common)
Not only two arrays but for an intersection of n arrays... Let's invent Array.prototype.intersect()
Array.prototype.intersect = function(...a) {
return [this,...a].reduce((p,c) => p.filter(e => c.includes(e)));
}
var arrs = [[0,2,4,6,8],[4,5,6,7],[4,6]],
arr = [0,1,2,3,4,5,6,7,8,9];
console.log(JSON.stringify(arr.intersect(...arrs)));
// or just do
console.log(JSON.stringify(["a","b","c","d"].intersect(["b","d","f","h"])));

How to create a list of unique items in JavaScript? [duplicate]

This question already has answers here:
Get all unique values in a JavaScript array (remove duplicates)
(91 answers)
Closed 1 year ago.
In my CouchDB reduce function I need to reduce a list of items to the unique ones.
Note: In that case it's ok to have a list, it will be a small number of items of string type.
My current way is to set keys of a object, then return the keys of that object
since the place the code can't use things like _.uniq for example.
I'd like to find a more elegant way to spell it than this.
function(keys, values, rereduce) {
// values is a Array of Arrays
values = Array.concat.apply(null, values);
var uniq = {};
values.forEach(function(item) { uniq[item] = true; });
return Object.keys(uniq);
}
The best method seem to be using ES6 and Set. Single line and faster* than above according to fiddle
const myList = [1,4,5,1,2,4,5,6,7];
const unique = [...new Set(myList)];
console.log(unique);
*tested in safari
2021 answer:
const unique = (arr) => [...new Set(arr)];
unique([1, 2, 2, 3, 4, 4, 5, 1]); // [1, 2, 3, 4, 5]
Here you just create a set from the given array and then convert it back to the array.
I measured performance and it's almost twice faster now than the approach proposed in the old answer I posted before. Also, it's just a one-liner.
Updated fiddle
Old answer just for the record:
Commonly, the approach you used is a good idea.
But I could propose a solution that will make the algorithm a lot faster.
function unique(arr) {
var u = {}, a = [];
for(var i = 0, l = arr.length; i < l; ++i){
if(!u.hasOwnProperty(arr[i])) {
a.push(arr[i]);
u[arr[i]] = 1;
}
}
return a;
}
As you can see we have only one loop here.
I've made an example that is testing both your and my solutions. Try to play with it.
An alternative that's suitable for small lists would be to ape the Unix command line approach of sort | uniq:
function unique(a) {
return a.sort().filter(function(value, index, array) {
return (index === 0) || (value !== array[index-1]);
});
}
This function sorts the argument, and then filters the result to omit any items that are equal to their predecessor.
The keys-based approach is fine, and will have better performance characteristics for large numbers of items (O(n) for inserting n items into a hashtable, compared to O(n log n) for sorting the array). However, this is unlikely to be noticeable on small lists. Moreover, with this version you could modify it to use a different sorting or equality function if necessary; with hash keys you're stuck with JavaScripts notion of key equality.
This should work with anything, not just strings:
export const getUniqueList = (a: Array<any>) : Array<any> => {
const set = new Set<any>();
for(let v of a){
set.add(v);
}
return Array.from(set);
};
the above can just be reduced to:
export const getUniqueValues = (a: Array<any>) => {
return Array.from(new Set(a));
};
:)
To get unique objects, you can use JSON.stringify and JSON.parse:
const arr = [{test: "a"}, {test: "a"}];
const unique = Array.from(new Set(arr.map(JSON.stringify))).map(JSON.parse);
console.log(unique);
Using Object.keys will give you strings if you put in integer arguments (uniq([1,2,3]) => ['1','2','3']. Here's one with Array.reduce:
function uniq(list) {
return list.reduce((acc, d) => acc.includes(d) ? acc : acc.concat(d), []);
}
This is an old question, I know. However, it is at the top of some google searches, so I wanted to add that you can combine the answers from #RobHague and #EugeneNaydenov using the following:
function unique(arr) {
const u = {};
return arr.filter((v) => {
return u[v] = !u.hasOwnProperty(v);
});
};
You can also ignore undefined values (often handy) by adding:
function unique(arr) {
const u = {};
return arr.filter((v) => {
return u[v] = (v !== undefined && !u.hasOwnProperty(v));
});
};
You can play with this solution here: https://jsfiddle.net/s8d14v5n/
I find the other answers to be rather complicated for no gain that I can see.
We can use the indexOf method of the Array to verify if an item exists in it before pushing:
const duplicated_values = ['one', 'one', 'one', 'one', 'two', 'three', 'three', 'four'];
const unique_list = [];
duplicated_values.forEach(value => {
if (unique_list.indexOf(value) === -1) {
unique_list.push(value);
}
});
console.log(unique_list);
That will work with any type of variable as well, even objects (given the identifier actually reference the same entity, merely equivalent objects are not seen as the same).
what about
function unique(list) {
for (i = 0; i<list.length; i++) {
for (j=i+1; j<list.length; j++) {
if (list[i] == list[j]) {
list.splice(j, 1);
}
}
}
}

Categories