I have parts of data tagged with IDs distributed in different collections.
I need to access this data directly with the ID, but I also need to loop over the data really fast.
var listOfPartA = {
34523: { foo: 7, bar: 123},
6435: { foo: 2, bar: 163},
3123: { foo: 3, bar: 223},
...
};
var listOfPartB = {
34523: { baz: 1},
6435: { baz: 4},
3123: { baz: 6},
...
};
If I need to get specific dataparts for an Id it's fast, but If I try to loop all the dataparts it's slow.
var listOfPartA = [
{ id: 34523, foo: 7, bar: 123},
{ id: 6435, foo: 2, bar: 163},
{ id: 3123, foo: 3, bar: 223},
...
];
var listOfPartB = [
{ id: 34523, baz: 1},
{ id: 6435, baz: 4},
{ id: 3123, baz: 6},
...
];
If I want to get specific dataparts for an ID of these objects it is slow, because I have to search for them manually, but If I loop over all dataparts it's fast.
Can't I have fast direct access and fast iteration?
Pre-index your array:
var listOfPartA = [
{id:34523, foo:7 bar:123},
...
];
var lookupPartA = {};
listOfPartA.forEach(function(x,i) {lookupPartA[x.id] = i;});
Now, you can loop quickly with the listOfPartA array, but also find quickly:
listOfPartA[lookupPartA[34523]]
Pre-index your object:
var lookupPartA = {
34523: { foo: 7, bar: 123},
...
};
var listOfIds = Object.keys(lookupPartA);
Now, you can find ids quickly in the lookupPartA object, but also loop quickly:
for (var i=0, l=listOfIds.length; i<l; i++)
lookupPartA[listOfIds[i]]
According to theses tests, arrays are always fasters than objects.
array vs object performance test
object vs array vs native linked list
benchmark comparison
Related
I am looking to take an array of objects, and convert it into an array of subarrays based on a chosen object property
for example:
[
{foo: 1, bar: a}, {foo: 2, bar: b}, {foo: 1, bar: c}, {foo: 2, bar: d}
]
Create subarrays with the foo property would become:
[
[
{foo: 1, bar: a}, {foo: 1, bar: c},
],
[
{foo: 2, bar: b}, {foo: 2, bar: d}
]
]
I can't think of an efficient way to this. I keep resorting to creating a set of all of the unique property values of my chosen value, and then brute forcing through it multiple times.
const distinctProperties = [...new Set(originalArray.map(item => item.foo))]
const newArray = distinctProperties.map(item => originalArray.filter(obj => obj.foo === item))
Thanks in advance for some advice here!
can be done with reduce. you can wrap this around another function to group by the key you want.
Here I'm grouping based on the value of foo and res will be like this
{
1: [{
bar: "a",
foo: 1
}, {
bar: "c",
foo: 1
}],
2: [{
bar: "b",
foo: 2
}, {
bar: "d",
foo: 2
}]
}
then I'm taking Object.values of this to get the array format you want
let a =[
{foo: 1, bar: 'a'}, {foo: 2, bar: 'b'}, {foo: 1, bar: 'c'}, {foo: 2, bar: 'd'}
]
let res= Object.values(a.reduce((acc,curr)=> {
if(!acc[curr.foo])acc[curr.foo]=[];
acc[curr.foo].push(curr)
return acc;
},{}))
console.log(res)
As a generalized function to take key name as input
let a =[
{foo: 1, bar: 'a'}, {foo: 2, bar: 'b'}, {foo: 1, bar: 'c'}, {foo: 2, bar: 'd'}
]
let groupByValue = (arr,key) => {
return Object.values(arr.reduce((acc,curr)=> {
if(!acc[curr[key]])acc[curr[key]]=[];
acc[curr[key]].push(curr)
return acc;
},{}))
}
let res1 = groupByValue(a,'foo')
let res2 = groupByValue(a,'bar')
console.log(res1)
console.log(res2)
I have an Array of Objects:
const array = [{id: 1, bar: "test" }, {id: 2, bar: "test2" }, {id: 3, bar: "test3" }]
I have a second array containing the ID's that I want to filter out of the first Array:
const ids = [1, 2]
How do I create a new Array of Objects without the ID's found in ids.
This is a fairly simple filter operation
const array = [{id: 1, bar: "test" }, {id: 2, bar: "test2" }, {id: 3, bar: "test3" }];
const ids = [1, 2];
var result = array.filter( x => !ids.includes(x.id));
console.log(result);
If you need to mutate the original array you can do like this:
const array = [{id: 1, bar: "test" }, {id: 2, bar: "test2" }, {id: 3, bar: "test3" }];
const ids = [1, 2];
ids.forEach(idToDelete => {
const index = array.findIndex(({ id }) => id === idToDelete);
array.splice(index, 1);
});
console.log(array);
If you need a new array you can do like this:
const array = [{id: 1, bar: "test" }, {id: 2, bar: "test2" }, {id: 3, bar: "test3" }];
const ids = [1, 2];
const result = array.filter(({ id }) => !ids.includes(id));
console.log(result);
You could also reassign a new array to the array variable:
let array = [{id: 1, bar: "test" }, {id: 2, bar: "test2" }, {id: 3, bar: "test3" }];
const ids = [1, 2];
array = array.filter(({ id }) => !ids.includes(id));
console.log(array);
Use Array.filter :
let array = [
{id: 1, bar: "test" },
{id: 2, bar: "test2" },
{id: 3, bar: "test3" }
];
let ids = [1,2];
let filteredArray = array.filter(row=>!ids.includes(row.id));
console.log(filteredArray);
Use this oneliner from lodash.
const _ = require("lodash");
let filteredArray = _.remove(array, el=>[1,2].includes(el.id))
Use filter and indexOf.
const arr = [{ id: 1, bar: 'test' }, { id: 2, bar: 'test2' }, { id: 3, bar: 'test3' }];
const ids = [1, 2];
const result = arr.filter(element => ids.indexOf(element.id) === -1);
console.log(result);
We can filter an array in JavaScript using Array filter()
const myArray = [{id: 1, bar: "test" }, {id: 2, bar: "test2" }, {id: 3, bar: "test3" }]
const ids = [1,2]
const resultArray = myArray.filter(item => !ids.includes(item.id));
console.log(resultArray);
In term of performance the best solution will be the next one:
let array = [{id: 1, bar: "test" }, {id: 2, bar: "test2" }, {id: 3, bar: "test3" }];
const ids = [1,2];
const idSet = new Set();
for (const id of ids) {
idSet.add(id);
}
array = array.filter(x => !set.has(x.id));
//const newArray if you need the initial array unmodified
In this case we perform two consequencial iteration instead of a nested one, so the time complexity will be O(n) instead of O(n^2);
##Edit
If you instead need the initial array to be mutated and not overwritten you can use this approach:
const ids = [1,2];
const array = [{id: 1, bar: "test" }, {id: 2, bar: "test2" }, {id: 3, bar: "test3" }];
for (const id of ids) {
const index = array.findIndex(x => x.id == id);
array.splice(index, 1);
}
In the second case the time complexity will be O(n*m), where n is array length and m is ids length.
I want to propose something wildly different.
In my case, I wanted to filter one list of unique IDs against another.
I was curious if regex could do it faster.
Such a method really only works with one-dimensional arrays of simple objects.
It's probably best if items a single regex 'word' (string of 0-9a-z_).
A list of ids works perfect.
array.filter works best on small datasets (1,000), usually slightly faster
regex worked 66% faster on large datasets (10,000)
regex speed advantage widens. 90% faster on 100,000.
On comparing two arrays of 1m items, filter didn't do anything for me after more than 90 seconds. Regex returned a result in six seconds.
In this case, the input is number[], and the output is string[], which works for my purposes, but you can use map to convert back to numbers if you need, .
var listlength = 10000;
function createArray() {
let arr = new Set();
for (let i = 0; i < listlength; i++) {
arr.add(Math.floor(Math.random() * listlength));
}
return arr;
}
function filter() {
let arr1 = Array.from(createArray());
let arr2 = Array.from(createArray());
let start = +new Date();
let arr3 = arr1.filter((n) => !arr2.includes(n));
console.log('filter', (+new Date() - start) + 'ms', arr1.length, arr2.length, arr3.length);
}
function regex() {
let arr1 = Array.from(createArray());
let arr2 = Array.from(createArray());
let start = +new Date();
let str1 = arr1.join(',') + ',';
str1 = str1.replace(new RegExp('\\b(' + arr2.join('|') + '),', 'g'), '');
let result = str1.split(',') // .map(e=>Number(e)); (to convert back to number[])
result.pop();
console.log('regex', (+new Date() - start) + 'ms', arr1.length, arr2.length, result.length);
}
for (let x = 0; x < 10; x++) {
console.log(`try ${x}`);
filter();
regex();
}
On my NodeJS app, sets of 100,000, regex more than 90% faster.
how can i return an array of objects taking from array of again one more level array. I am using push.
is there any better way to achieve this
let a = [{b: [{c: "k"}]}]
let o = []
a.forEach(so => {so.b.forEach(obc => o.push(obc))})
console.log(o)
I'd use flatMap() instead:
const a = [{
b: [{
foo: 'foo'
}]
},
{
b: [{
c: "k"
},
{
bar: 'bar'
}
]
}
];
const o = a.flatMap(({ b }) => b);
console.log(o);
(but this is a relatively new method, so if you want to use it and still support older environments, be sure to include a polyfill)
Lacking that, you can also improve your existing code by using concat() with the inner array instead of iterating over each inner item:
const a = [{
b: [{
foo: 'foo'
}]
},
{
b: [{
c: "k"
},
{
bar: 'bar'
}
]
}
];
let o = [];
a.forEach(({ b }) => {
o = o.concat(b);
});
console.log(o);
Try
let a = [{b: [{c: "k"}]}]
let o =a[0].b
console.log(o)
I have a big array of objects and i need to get the objects that have the propertie def set. No mather the value...
Thanks in advance.
You can use hasOwnProperty to check if a property is present, and Array.prototype.filter to filter only those items.
objArray = [ { def: 1, bar: 2}, { foo: 3, bar: 4}, { def: 5, bar: 6} ];
var result = objArray.filter(item => item.hasOwnProperty('def'));
console.log(result);
for es5 compatibility
objArray = [{
def: 1,
bar: 2
}, {
foo: 3,
bar: 4
}, {
def: 5,
bar: 6
}];
var result = objArray.filter(function(item) {
return item.hasOwnProperty('def')
});
console.log(result);
There is not such function in lodash although you can try following code
`let aFilteredArray = [];
_.forEach(YourArray,function(oElement){
if(!_.isEmpty(oElement.def)){
aFilteredArray.push(oElement);
}
};
I am looking for the most efficient way to extract a subset of elements from a javascript object. Suppose I have many records in the form of javascript objects
var records = [
{ foo: 123, bar: 456, baz: 789, boo: [1,2,3] },
{ foo: 345, bar: 754, baz: 853, boo: [4,3,2] },
{ foo: 321, bar: 234, baz: 443, boo: [5,2,1] }
]
And for each of these objects I want to extract the same keys, which are stored in an array, e.g.
var keys = ["bar", "boo"]
The native way to do so would be along the lines of
out = [];
for(var i = 0; i < records.length; i++){
out[i] = {};
for(var j = 0; j < keys.length; j++){
var field = keys[j];
out[i][field] = records[i][field]
}
}
console.log(out)
Is there a faster / more elegant way?
Not sure about speed, but a more concise notation could be (assuming all keys are present in each record):
var out = records.map(function(v) {
return keys.reduce(function(o, k) {
return (o[k] = v[k], o);
}, {});
});
I can't think of a better Big O notation for your problem, but looking at the current data, a good algoritm may not be your primary focus?
In ECMA-script 5 the base Object contains a keys method:
a = {a: '1', b: '2', c: '3'}
Object.keys(a)
// [ 'a', 'b', 'c' ]