Related
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);
What am I doing wrong here?
var locations = [
{ id: 1, name: 'N'},
{ id: 2, name: 'P'}
]
var employee = { location_id: 1 }
locations.filter((location) => {
return location.id == employee.location_id
});
console.log(locations);
this returns undefined when I'm trying to make it return { id: 1, name: 'N'}.
filter() function is not mutable - which means it returns a new array with the filtered objects and do not 'mutate' the original array - you must assign it to another variable - see demo below:
locations = [
{ id: 1, name: 'N'},
{ id: 2, name: 'P'}
]
employee = { location_id: 1 }
var result = locations.filter((location) => {
return location.id == employee.location_id
})
console.log(result);
You need a variable for the result of filtering with Array#filter
The filter() method creates a new array with all elements that pass the test implemented by the provided function.
var locations = [
{ id: 1, name: 'N'},
{ id: 2, name: 'P'}
],
employee = { location_id: 1 },
result = locations.filter((location) => {
return location.id == employee.location_id
});
console.log(result);
You need to store the result of .filter(). It doesn't mutate the original array.
On a side note, you can shorten your callback function by removing the curly brackets and return statement.
locations = locations.filter(loc => loc.id == employee.location_id);
My array looks like this:
array = [object {id: 1, value: "itemname"}, object {id: 2, value: "itemname"}, ...]
all my objects have the same attibutes, but with different values.
Is there an easy way I can use a WHERE statement for that array?
Take the object where object.id = var
or do I just need to loop over the entire array and check every item? My array has over a 100 entries, so I wanted to know if there was a more efficient way
Use Array.find:
let array = [
{ id: 1, value: "itemname" },
{ id: 2, value: "itemname" }
];
let item1 = array.find(i => i.id === 1);
Array.find at MDN: https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Array/find
I'd use filter or reduce:
let array = [
{ id: 1, value: "itemname" },
{ id: 2, value: "itemname" }
];
let item1 = array.filter(item => item.id === 1)[0];
let item2 = array.reduce((prev, current) => prev || current.id === 1 ? current : null);
console.log(item1); // Object {id: 1, value: "itemname"}
console.log(item2); // Object {id: 1, value: "itemname"}
(code in playground)
If you care about iterating over the entire array then use some:
let item;
array.some(i => {
if (i.id === 1) {
item = i;
return true;
}
return false;
});
(code in playground)
You can search a certain value in array of objects using TypeScript dynamically if you need to search the value from all fields of the object without specifying column
var searchText = 'first';
let items = [
{ id: 1, name: "first", grade: "A" },
{ id: 2, name: "second", grade: "B" }
];
This below code will search for the value
var result = items.filter(item =>
Object.keys(item).some(k => item[k] != null &&
item[k].toString().toLowerCase()
.includes(searchText.toLowerCase()))
);
Same approach can be used to make a Search Filter Pipe in angularjs 4 using TypeScript
I had to declare the type to get it to work in typescript:
let someId = 1
array.find((i: { id: string; }) => i.id === someId)
You'll have to loop over the array, but if you make a hashmap to link each id to an index and save that, you only have to do it once, so you can reference any objeft after that directly:
var idReference = myArray.reduce(function( map, record, index ) {
map[ record.id ] = index;
return map;
}, {});
var objectWithId5 = myArray[ idReference["5"] ];
This does assume all ids are unique though.
I have the following issue: In my app, I receive from the backend an string containing an comma separated list of numbers, which i convert to an array using join(). Then i get from another method an array containing several objects, like in this example:
strArray = [1,3]
objArray = [{'id':1,'name':'A'},
{'id':2,'name':'B'},
{'id':3,'name':'C'}]
I need to create another array based on this two array, expecting the following result:
resultArray = [{'id':1,'name':'A','selected': true},
{'id':2,'name':'B','selected': false},
{'id':3,'name':'C','selected': true}]
I've tried using map and function but without success. I'm quite new in javascript.
Would this help?
objArray.map(obj => {
obj['selected'] = strArray.indexOf(obj.id) != -1;
return obj;
});
try this:
strArray = [1, 3]
objArray = [{
'id': 1,
'name': 'A'
}, {
'id': 2,
'name': 'B'
}, {
'id': 3,
'name': 'C'
}]
var res = objArray.map(x => Object.assign(x, {
sel: strArray.includes(x.id)
}))
console.log(res)
but consider browser support for the proposed methods.
Hope this helps. By using simple .map
var strArray = [1,3];
var objArray = [{'id':1,'name':'A'},
{'id':2,'name':'B'},
{'id':3,'name':'C'}];
var resultArray = objArray.map(function(obj){
obj.selected = strArray.indexOf(obj.id) > -1;
return obj;
});
console.log(resultArray);
With map:
objArray.map(function(item){
return {id: item.id, name: item.name,selected: strArray.indexOf(item.id) > -1};
})
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