Related
my problem might not be as challenging as some other similar questions but they were a little to much for me.
I have an array of objects that I need to filter by name against a string array of names, if the names match I want to remove the object with the name that matches
so like the following:
nameObjects = [{name: 'name3', value: 'some val'},{name: 'name1', value:'some other val'}]
names = ['name1','name2','name3']
I've tried the following just using for loops but I'm sure that there is a quicker (and correct lol) filter method that works
for(i=0; i < this.names.length; i++){
for(j=0; j < this.nameObjects.length; j++){
if(this.names[i] === this.nameObjects[j].name){
this.files.splice(i,this.nameObjects[j])
}
}
}
also sorry for the poor logic ^
You should not mutate the array while you are looping over it.
You can simply use Array.prototype.filter with Array.prototype.includes to get the desired result
const nameObjects = [{name: 'name3', value: 'some val'},{name: 'name1', value:'some other val'}];
const names = ['name2','name3'];
const res = nameObjects.filter(obj => !names.includes(obj.name));
console.log(res);
const nameObjects = [
{ name: "name3", value: "some val" },
{ name: "name1", value: "some other val" },
];
const names = ["name1", "name2"];
const result = nameObjects.filter(obj => !names.includes(obj.name));
console.log(result);
I am making a dropdown from json file containing array of objects, the problem is some of the objects have same IDs, and I want to extract only the first objects with unique ID (for example 1, then take the second object with unique ID 2 etc..) and put them in a list. That is, I need a list with unique IDs only.
What I have tried so far:
var distinctId = [];
for (var i = 0; i < data.length; i++) {
var id = data[i]["id"];
if (distinctId[id] == undefined) {
distinctId[id] = [];
}
distinctId[id].push(data[i]);
console.log(data[i]);
}
The json file looks something like this:
[
{
id: 1,
field1: ...,
field2: ...
},
{
id: 1,
field1: ...,
field2: ...
},
{
id: 2,
field1: ...,
field2: ...
},
{
id: 2,
field1: ...,
field2: ...
},
{
id: 3,
field1: ...,
field2: ...
},
{
id: 3,
field1: ...,
field2: ...
},
]
If all you wish to do is get the first two unique ids of your objects you can do this by mapping your array to an array of id's using .map and destructing assignment.
Once you have done this you can use a set to remove all the duplicate's from the array. Lastly, you can use .splice to keep the first 2 unique ids from your array:
const arr = [{id:1,field1:'foo',field2:'bar'},{id:1,field1:'foo',field2:'bar'},{id:2,field1:'foo',field2:'bar'},{id:2,field1:'foo',field2:'bar'},{id:3,field1:'foo',field2:'bar'},{id:3,field1:'foo',field2:'bar'}],
res = [...new Set(arr.map(({id}) => id))].splice(0, 2);
console.log(res);
If you wish to have an array of objects which are unique you can use .reduce to create a new array. Essentially the new array is created by adding the first object from the array into it, then checking if the next object has the same id as that object. To do this we use .every. If it does have the same id we go to the next object, if the id is different then we can add this to our array. Then when we look at our next object we check if it matches any of the now 2 object id's in our array, if it doesn't we can add it and so on.
const arr = [{id:1,field1:'foo1',field2:'bar1'},{id:1,field1:'foo2',field2:'bar2'},{id:2,field1:'foo3',field2:'bar3'},{id:2,field1:'foo4',field2:'bar4'},{id:3,field1:'foo5',field2:'bar5'},{id:3,field1:'foo6',field2:'bar6'}],
res = arr.splice(1).reduce((acc, elem) => acc.every(({id}) => id != elem.id) ? [...acc, elem] : acc, [arr[0]]);
console.log(res);
You can reduce your array, and check if there is an element that matches your criteria:
your_json_array.reduce((destArray, obj) => {
if (destArray.findIndex(i => i.id === obj.id) < 0) {
return destArray.concat(obj);
} else {
return destArray;
}
}, []);
That will give you another array with the desired data.
You can achieve this by using something along the lines of this, however it may be a better idea to do what I've done in my second example. Within the second example, you can see that it's storing a list of all duplicated ID's, the first example will only work for an even number of duplicated ID's... I.E. if there were three objects with the id property set to a value of 1, you'd still get the value 1 within the arrayvariable.
I mean there are other ways in which you could achieve this, you could use a filter function in there somewhere, etc. If you require more documentation on how to use the reduce function, I'd suggest the MDN Docs.
Finally with example 3, that's simply removing all duplicates, making use of more modern syntax and features such as destructuring.
Example 1
var objects = [{id: 1,a:'x'},{id:1,a:'x'},{id:2,a:'x'},{id:3,a:'x'}];
var array = objects.reduce((a, i) => {
a.indexOf(i.id) == -1 ? a.push(i.id) : a.splice(a.indexOf(i.id), 1);
return a;
}, []);
console.log(array);
Example 2
var objects = [{id: 1,a:'x'},{id:1,a:'x'},{id:2,a:'x'},{id:3,a:'x'}];
var array = objects.reduce((a, i) => {
objects.filter(e => e.id == i.id).length == 1 ? a.push(i.id) : null;
return a;
}, []);
console.log(array);
Example 3
const objects = [{id: 1,a:'x'},{id:1,a:'x'},{id:2,a:'x'},{id:3,a:'x'}];
const removeDuplicates = ([...o]) => o.reduce((a, i) => {
a.indexOf(i.id) == -1 ? a.push(i) : null;
return a
}, []);
console.log(removeDuplicates(objects));
1) To remove duplicates from the original array you can use filter() in conjunction with the optional argument that is passed as this to the filtering method.
2) To get an array with unique ids you can use map() on the previous result.
This is shown on next example:
const input = [
{id: 1, field1: "f1", field2: "f2"},
{id: 1, field1: "f1", field2: "f2"},
{id: 2, field1: "f1", field2: "f2"},
{id: 2, field1: "f1", field2: "f2"},
{id: 3, field1: "f1", field2: "f2"},
{id: 3, field1: "f1", field2: "f2"},
];
// Remove duplicates elements.
let res = input.filter(
function({id}) {return !this.has(id) && this.add(id)},
new Set()
);
console.log("No duplicates:", res);
// Get a map with only the IDs.
let ids = res.map(({id}) => id);
console.log("Ids:", ids);
I created an immutable map (with Immutable-JS) from a list of objects:
var result = [{'id': 2}, {'id': 4}];
var map = Immutable.fromJS(result);
Now i want to get the object with id = 4.
Is there an easier way than this:
var object = map.filter(function(obj){
return obj.get('id') === 4
}).first();
Essentially, no: you're performing a list lookup by value, not by index, so it will always be a linear traversal.
An improvement would be to use find instead of filter:
var result = map.find(function(obj){return obj.get('id') === 4;});
The first thing to note is that you're not actually creating a map, you're creating a list:
var result = [{'id': 2}, {'id': 4}];
var map = Immutable.fromJS(result);
Immutable.Map.isMap(map); // false
Immutable.List.isList(map); // true
In order to create a map you can use a reviver argument in your toJS call (docs), but it's certainly not the most intuitive api, alternatively you can do something like:
// lets use letters rather than numbers as numbers get coerced to strings anyway
var result = [{'id': 'a'}, {'id': 'b'}];
var map = Immutable.Map(result.reduce(function(previous, current) {
previous[ current.id ] = current;
return previous;
}, {}));
Immutable.Map.isMap(map); // true
Now we have a proper Immutable.js map which has a get method
var item = Map.get('a'); // {id: 'a'}
It may be important to guarantee the order of the array. If that's the case:
Use an OrderedMap
Do a set method on the OrderedMap at each iteration of your source array
The example below uses "withMutations" for better performance.
var OrderedMap = Immutable.OrderedMap
// Get new OrderedMap
function getOm(arr) {
return OrderedMap().withMutations(map => {
arr.forEach(item => map.set(item.id, item))
})
}
// Source collection
var srcArray = [
{
id: 123,
value: 'foo'
},
{
id: 456,
value: 'bar'
}
]
var myOrderedMap = getOm(srcArray)
myOrderedMap.get(123)
// --> { id: 123, value: 'foo' }
myOrderedMap.toObject()
// --> { 123: {id: 123, value: 'foo'}, 456: {id: 456, value: 'bar'} }
myOrderedMap.toArray()
// --> [ {id: 123, value: 'foo'}, { id: 456, value: 'bar' } ]
When using fromJS for array, you'll get List not map. It will be better and easier if you create a map. The following code will convert the result into Immutable map.
const map = result.reduce((map, json) =>
map.set(json.id, Immutable.fromJS(json))
, Map());
Now, you can
map.get('2'); //{'id': 2}
Note, if the result has nested structure and if that has array, it will be a List with the above code.
With ES2015 syntax (and constants):
const result = map.find(o => o.get('id') === 4);
Is there already a way thats easier? I don't know. but you can write your own function. Something like this should work:
var myFunc = function(id){
var object = map.filter(function(obj){return obj.get('id') === id}).first();
return object;
}
Then you would just do:
var myObj = myFunc(4);
I have an array of objects and I want to get a new array from it that is unique based only on a single property, is there a simple way to achieve this?
Eg.
[ { id: 1, name: 'bob' }, { id: 1, name: 'bill' }, { id: 1, name: 'bill' } ]
Would result in 2 objects with name = bill removed once.
Use the uniq function
var destArray = _.uniq(sourceArray, function(x){
return x.name;
});
or single-line version
var destArray = _.uniq(sourceArray, x => x.name);
From the docs:
Produces a duplicate-free version of the array, using === to test object equality. If you know in advance that the array is sorted, passing true for isSorted will run a much faster algorithm. If you want to compute unique items based on a transformation, pass an iterator function.
In the above example, the function uses the objects name in order to determine uniqueness.
If you prefer to do things yourself without Lodash, and without getting verbose, try this uniq filter with optional uniq by property:
const uniqFilterAccordingToProp = function (prop) {
if (prop)
return (ele, i, arr) => arr.map(ele => ele[prop]).indexOf(ele[prop]) === i
else
return (ele, i, arr) => arr.indexOf(ele) === i
}
Then, use it like this:
const obj = [ { id: 1, name: 'bob' }, { id: 1, name: 'bill' }, { id: 1, name: 'bill' } ]
obj.filter(uniqFilterAccordingToProp('abc'))
Or for plain arrays, just omit the parameter, while remembering to invoke:
[1,1,2].filter(uniqFilterAccordingToProp())
If you want to check all the properties then
lodash 4 comes with _.uniqWith(sourceArray, _.isEqual)
A better and quick approach
var table = [
{
a:1,
b:2
},
{
a:2,
b:3
},
{
a:1,
b:4
}
];
let result = [...new Set(table.map(item => item.a))];
document.write(JSON.stringify(result));
Found here
You can use the _.uniqBy function
var array = [ { id: 1, name: 'bob' }, { id: 2, name: 'bill' }, { id: 1, name: 'bill' },{ id: 2, name: 'bill' } ];
var filteredArray = _.uniqBy(array,function(x){ return x.id && x.name;});
console.log(filteredArray)
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.5/lodash.js"></script>
In the above example, filtering is based on the uniqueness of combination of properties id & name.
if you have multiple properties for an object.
then to find unique array of objects based on specific properties, you could follow this method of combining properties inside _.uniqBy() method.
I was looking for a solution which didn't require a library, and put this together, so I thought I'd add it here. It may not be ideal, or working in all situations, but it's doing what I require, so could potentially help someone else:
const uniqueBy = (items, reducer, dupeCheck = [], currentResults = []) => {
if (!items || items.length === 0) return currentResults;
const thisValue = reducer(items[0]);
const resultsToPass = dupeCheck.indexOf(thisValue) === -1 ?
[...currentResults, items[0]] : currentResults;
return uniqueBy(
items.slice(1),
reducer,
[...dupeCheck, thisValue],
resultsToPass,
);
}
const testData = [
{text: 'hello', image: 'yes'},
{text: 'he'},
{text: 'hello'},
{text: 'hell'},
{text: 'hello'},
{text: 'hellop'},
];
const results = uniqueBy(
testData,
item => {
return item.text
},
)
console.dir(results)
In case you need pure JavaScript solution:
var uniqueProperties = {};
var notUniqueArray = [ { id: 1, name: 'bob' }, { id: 1, name: 'bill' }, { id: 1, name: 'bill' } ];
for(var object in notUniqueArray){
uniqueProperties[notUniqueArray[object]['name']] = notUniqueArray[object]['id'];
}
var uniqiueArray = [];
for(var uniqueName in uniqueProperties){
uniqiueArray.push(
{id:uniqueProperties[uniqueName],name:uniqueName});
}
//uniqiueArray
unique array by id property with ES6:
arr.filter((a, i) => arr.findIndex(b => b.id === a.id) === i); // unique by id
replace b.id === a.id with the relevant comparison for your case
I am trying to filter an array of objects, based on another. The common property id id.
I am not sure filter + each is the best way to do it or map reduce. Anyway, below code doesn't work as out is empty list.
var aaa = [
{name: "AAA", id: 845},
{name: "BBB", id: 839},
{name: "CCC", id: 854}
];
var bbb = [
{id: 839},
{id: 854}
];
var out = _.filter(aaa, function(val){
return _.each(this, function(val2){
return val['id'] === val2['id']
});
}, bbb);
Just create a "set" of the valid ids and use that "set" to do the filtering:
var aaa = [
{name: "AAA", id: 845},
{name: "BBB", id: 839},
{name: "CCC", id: 854}
];
var bbb = [
{id: 839},
{id: 854}
];
var ids = {};
_.each(bbb, function (bb) { ids[bb.id] = true; });
var out = _.filter(aaa, function (val) {
return ids[val.id];
}, bbb);
Filling ids is fast, it's in n * amortized O(1), i.e O(n). Same holds for the filtering.
If you use each(…) in the inner loop, you will have O(n²). For bigger data sets this would become very slow. Also the additional nesting make the code more difficult to read/understand at first glance.
See that code snipped in action: http://jsfiddle.net/SMtX5/
you can use _.find to filter:
_.filter(aaa, function(a){
return _.find(bbb, function(b){
return b.id === a.id;
});
});
You can use _.some(list, [iterator], [context]).
It returns true if any of the values in the list pass the iterator truth test.
var out = _.filter(aaa, function(val){
return _.some(this,function(val2){
return val2['id'] === val['id'];
});
}, bbb);
Here is jsfiddle. http://jsfiddle.net/h98ej/
bbb = bbb.map(_ => _.id) && aaa.filter(_ => bbb.indexOf( _.id ) > -1)
You just need pure JS array functions to do that assuming your use case.