Suppose I am having two arrays namely namesArray and names as below
var namesArray = [{"name":"Charlie","age":3},{"name":"Dog","age":1},{"name":"Baker","age":7},{"name":"Abel","age":9}];
var names = ['Baker', 'Dog', 'Abel', 'Charlie'];
Can I achieve the following in UnderscoreJS so that sort the array named namesArray in a order so that all the name elements of namesArray will be in the same order of names .
In plain Javascript, you could use Array#sort with an object as reference for the sort order.
var namesArray = [{ "name": "Charlie", "age": 3 }, { "name": "Dog", "age": 1 }, { "name": "Baker", "age": 7 }, { "name": "Abel", "age": 9 }],
names = ['Baker', 'Dog', 'Abel', 'Charlie'],
hash = Object.create(null);
names.forEach(function (a, i) {
hash[a] = i + 1;
});
namesArray.sort(function (a, b) {
return (hash[a.name] || 0) - (hash[b.name] || 0);
});
console.log(namesArray);
Look up the index of each name in sort(). Not as performant as creating hash of indexes but chances are it's not that critical either
namesArray.sort(function(a,b){
return names.indexOf(a.name) - names.indexOf(b.name);
});
There is not lot to do with underscrore but you can do it like this:
I think using hash like what Nina does would be better than indexOf with respect to performance.
var namesArray = [{ "name": "Charlie", "age": 3 }, { "name": "Dog", "age": 1 }, { "name": "Baker", "age": 7 }, { "name": "Abel", "age": 9 }];
var names = ['Baker', 'Dog', 'Abel', 'Charlie'];
var sorted = _.sortBy(namesArray, o => names.indexOf(o.name));
console.log(sorted);
<script src="https://cdnjs.cloudflare.com/ajax/libs/underscore.js/1.8.3/underscore.js"></script>
Related
I have an array like this:
var clients=[{"id":1,"name":"john","age":20},
{"id":3,"name":"dean","age":23},
{"id":12,"name":"harry","age":14},
{"id":1,"name":"sam","age":22},
{"id":13,"name":"Bolivia","age":16},
{"id":7,"name":"sabi","age":60},
{"id":7,"name":"sahra","age":40},
{"id":4,"name":"natie","age":53},{"id":7,"name":"many","age":22}]
I want to find the duplicate objects and cluster them like this:
[
{
"id":1,
"clients":[
{"id":1,"name":"john","age":20},
{"id":1,"name":"sam","age":22}
]
},
{
"id":7,
"clients":[
{"id":7,"name":"sabi","age":60},
{"id":7,"name":"sahra","age":40},
{"id":7,"name":"many","age":22}
]
}
]
can I do that with filter() like this:clients.reduce(//code hier)?
reduce() is tailor made for this. When you want to aggregate over an array and get a computed result, you should use reduce().
find() is another array method, which helps in finding an array element based on a condition (here the matching of id property).
var clients=[{"id":1,"name":"john","age":20},
{"id":3,"name":"dean","age":23},
{"id":12,"name":"harry","age":14},
{"id":1,"name":"sam","age":22},
{"id":13,"name":"Bolivia","age":16},
{"id":7,"name":"sabi","age":60},
{"id":7,"name":"sahra","age":40},
{"id":4,"name":"natie","age":53},{"id":7,"name":"many","age":22}]
let ans = clients.reduce((agg,x,index) => {
let findI = agg.find( a =>
a.id === x.id
);
if(findI) findI.clients.push(x);
else {
agg.push({
id : x.id,
clients : [x]
});
}
return agg;
},[]);
console.log(ans);
The simplest solution would be to loop over the clients and check for an existing object with the same id. If yes, push to clients array. Or else, just create one.
var clients = [{ "id": 1, "name": "john", "age": 20 },
{ "id": 3, "name": "dean", "age": 23 },
{ "id": 12, "name": "harry", "age": 14 },
{ "id": 1, "name": "sam", "age": 22 },
{ "id": 13, "name": "olivia", "age": 16 },
{ "id": 7, "name": "sabi", "age": 60 },
{ "id": 7, "name": "sahra", "age": 40 },
{ "id": 4, "name": "natie", "age": 53 }, { "id": 7, "name": "kany", "age": 22 }]
const groups = [];
for (let client of clients) {
const existingGroup = groups.find(group => group.id == client.id)
if (existingGroup)
existingGroup.clients.push(client);
else {
groups.push({ id: client.id, clients: [client] });
}
}
console.log(groups);
You can reassign the original object with the temporary object just used for this, and continue with your business logic, which I believe is the one you are looking for.
I have two arrays.Second arrayB has some elements identical to arrayA. Now after comparing the arrays arrayA should have only those values those are not in arrayB. Please tell me best way to do it.
let arrayA = [{ "displayName": "John" }, { "displayName": "Sandra" },{ "displayName": "Peter" }]
let arrayB = [{ "name": "Bobby" }, { "name": "John" }, { "name": "Sandra" }]
arrayA.forEach(function(cust, index) {
arrayB.forEach(function(comp) {
if (comp.name == cust.displayName) {
delete arrayA[index]
}
})
})
console.log("Final"+JSON.stringify(arrayA))
Output -> Final[null,null,{"displayName":"Peter"}]
Filter and only keep the ones that do not exist in the other array
let arrayA = [{ "displayName": "John" }, { "displayName": "Sandra" },{ "displayName": "Peter" }]
let arrayB = [{ "name": "Bobby" }, { "name": "John" }, { "name": "Sandra" }]
arrayA = arrayA.filter(a =>
!arrayB.find(b => a.displayName === b.name)
);
console.log("Final"+JSON.stringify(arrayA))
To remove the elements, that aren't contained by arrayB you can use map() and filter():
arrayB = arrayB.map((key) => key.name)
arrayA = arrayA.filter((key) => arrayB.includes(key.displayName))
In the first line you'll get an array with only names
In the second line you'll remove from arrayA elements, that aren't in arrayB
You can also add map():
arrayB = arrayB.map((key) => key.name)
arrayA = arrayA.filter((key) => arrayB.includes(key.displayName))
.map((key) => key.displayName)
So you'll have in second array only names, but not objects.
let arrayA = [{ "displayName": "John" }, { "displayName": "Sandra" },{ "displayName": "Peter" }]
let arrayB = [{ "name": "Bobby" }, { "name": "John" }, { "name": "Sandra" }]
const shouldFilterOutByName = {};
for (let item of arrayB) {
shouldFilterOutByName[item.name] = true;
}
const filteredAry = arrayA.filter(item => !shouldFilterOutByName[item.displayName]);
console.log(filteredAry);
Taplar's solution is probably the one you want. The reason I haven't deleted my answer is in case time complexity is important. Taplar's solution has time complexity of O(n^2) and my solution is O(n).
I have an array of objects (I think!) and I need to extract the property name (for example "nickname") from a given object.
With
var VarObjAndValue = newArr[0];
I get the individual arrays (for example Object { nickname: “jhonny” }).
How can I now extract the property name "nickname" from the object above?
Listing the keys with
var listPropertyNames = Object.keys(newArr);
only provides sequential numbers from 0 to 6 rather than the desired keys names..
var StrToInclude = ["nickname", "name", "surname", "sex", "dob", "email", "phone"];
var newArr=[]; //Key name + its value
for (var i=0; i<StrToInclude.length; i++) {
temp_obj = {};
temp_obj[StrToInclude[i]] = document.getElementById(StrToInclude[i]).value;
newArr.push(temp_obj);
}
console.log('newArr --> = ',newArr);
/**
* newArr = [
* { "nickname": “jhonny” },
* { "name": “jonathan” },
* { "surname": “ross” },
* { "sex": “male” },
* { "dob": “22/02/1984” },
* { "email": “j#yahoo.com” },
* { "phone": "123" }
* ]
*/
var VarObjAndValue = newArr[0];
console.log('VarObjAndValue --> = ',VarObjAndValue); //if i=0 ----> Object { nickname: “jhonny” }
var VarObjAndValue = newArr[1];
console.log('VarObjAndValue --> = ',VarObjAndValue); //if i=1 ----> Object { name: "jonathan" }
var listPropertyNames = Object.keys(newArr);
console.log('listPropertyNames --> = ',listPropertyNames); //Array(7) [ "0", "1", "2", "3", "4", "5", "6" ] (not useful for this...)
newArr.map(obj => Object.keys(obj)).flat()
or newArr.map(obj => Object.keys(obj)[0])
or from dave's comment
newArr.reduce((keys, o) => [...keys, ...Object.keys(o)], [])
gives you all property names as an array
Not sure if this is what you want, but you have already gotten those property names in StrToInclude
const newArr =
[
{
"nickname": "jhonny"
},
{
"name": "jonathan"
},
{
"surname": "ross"
},
{
"sex": "male"
},
{
"dob": "22/02/1984"
},
{
"email": "j#yahoo.com"
},
{
"phone": "123"
}
]
console.log(newArr.map(obj => Object.keys(obj)[0]))
You are very close to getting the right answer. Since newArr is an Array, the keys are numeric keys. All you have to do is go through each element is the Array of Objects to extract the keys. Something like this should do nicely:
for(let i = 0;i<newArr.length;i++){
console.log(Object.keys(newArr[i])); //Will go through the whole array and give you the keys of every object in it
}
You can simply do by looping over the array and using destructuring operator with the desired property name.
const arr = [
{
nickname: "abdullah"
},
{
age: 27
}
];
arr.forEach(({nickname}) => {
if (nickname) {
console.log(`Thats the property we want to extract: ${nickname}`);
break; // if you are not expecting this property name in other objects, otherwise no need to break
}
});
I have an array of objects like this:
[ {"name": "apple", "id": "apple_0"},
{"name": "dog", "id": "dog_1"},
{"name": "cat", "id": "cat_2"}
]
I want to insert another element, also named apple, however, because I don't want duplicates in there, how can I use lodash to see if there already is an object in the array with that same name?
You can use Lodash _.find() like this.
var data = [ {"name": "apple", "id": "apple_0"},
{"name": "dog", "id": "dog_1"},
{"name": "cat", "id": "cat_2"}
]
if(!_.find(data, {name: 'apple'})) {
data.push({name: 'apple2'});
}
console.log(data)
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.15.0/lodash.min.js"></script>
Reference documentation: https://lodash.com/docs/4.17.14#find
This is Form
_.has(object, path)
Example:
const countries = { country: { name: 'Venezuela' } }
const isExist = _.has(countries, 'country.name')
// isExist = true
For more information Document Lodash
You can use Array.prototype.find() or lodash's _.find():
const addItem = (arr, item) => {
if(!arr.find((x) => x.name === item.name)) { // you can also change `name` to `id`
arr.push(item);
}
};
const arr = [
{"name": "apple", "id": "apple_0"},
{"name": "dog", "id": "dog_1"},
{"name": "cat", "id": "cat_2"}
];
addItem(arr, { "name": "apple", "id": "apple_0" });
addItem(arr, { "name": "pear", "id": "pear_3" });
console.log(arr);
And a bit shorter but less readable version:
const addItem = (arr, item) => arr.find((x) => x.name === item.name) || arr.push(item); // you can also change `name` to `id`
const arr = [
{"name": "apple", "id": "apple_0"},
{"name": "dog", "id": "dog_1"},
{"name": "cat", "id": "cat_2"}
];
addItem(arr, { "name": "apple", "id": "apple_0" });
addItem(arr, { "name": "pear", "id": "pear_3" });
console.log(arr);
Here is an other example with lodash
var a = [ {"name": "apple", "id": "apple_0"},
{"name": "dog", "id": "dog_1"},
{"name": "cat", "id": "cat_2"}
]
var b = _.find(a, ['name', "apple2"]);
if(_.isObject(b)){
console.log('exists')
}else{
console.log('insert new')
}
https://jsfiddle.net/jorge182/s4og07jg/
This is what worked for me (after testing out the different solutions):
addItem(items, item) {
let foundObject = _.find(items, function(e) {
return e.value === item.value;
});
if(!foundObject) {
items.push(item);
}
return items;
}
If you're interested in inserting in the array only one value, then using _.find could be an option. However, if you were interested in inserting one or more than one, I'd suggest using _.unionBy instead:
var currentArr = [{
"name": "apple",
"id": "apple_0"
}, {
"name": "dog",
"id": "dog_1"
}, {
"name": "cat",
"id": "cat_2"
}],
arrayOneValue = [{
"name": "apple",
"id": "apple_0"
}],
arrayTwoValues = arrayOneValue.concat({
"name": "lemon",
"id": "lemon_0"
})
console.log(_.unionBy(currentArr, arrayOneValue, 'name'));
console.log(_.unionBy(currentArr, arrayTwoValues, 'name'));
// It also allow you to perform the union using more than one property
console.log(_.unionBy(currentArr, arrayTwoValues, 'name', 'id'));
<script src="https://cdn.jsdelivr.net/lodash/4.16.4/lodash.min.js"></script>
Here are three ways of achieving this using lodash 4.17.5:
Say you want to add object entry to an array of objects numbers, only if entry does not exist already.
let numbers = [
{ to: 1, from: 2 },
{ to: 3, from: 4 },
{ to: 5, from: 6 },
{ to: 7, from: 8 },
{ to: 1, from: 2 } // intentionally added duplicate
];
let entry = { to: 1, from: 2 };
/*
* 1. This will return the *index of the first* element that matches:
*/
_.findIndex(numbers, (o) => { return _.isMatch(o, entry) });
// output: 0
/*
* 2. This will return the entry that matches. Even if the entry exists
* multiple time, it is only returned once.
*/
_.find(numbers, (o) => { return _.isMatch(o, entry) });
// output: {to: 1, from: 2}
/*
* 3. This will return an array of objects containing all the matches.
* If an entry exists multiple times, if is returned multiple times.
*/
_.filter(numbers, _.matches(entry));
// output: [{to: 1, from: 2}, {to: 1, from: 2}]
/*
* 4. This will return `true` if the entry exists, false otherwise.
*/
_.some(numbers, entry);
// output: true
If you want to return a Boolean (i.e., assuming that you are not using _.some()), in the first case, you can simply check the index value that is being returned:
_.findIndex(numbers, (o) => { return _.isMatch(o, entry) }) > -1;
// output: true
Lodash documentation is great source of examples and experimentation.
Using jQuery, I would like to use an array of ids to find the objects inside the allObjects array that have the matching Id value.
var arrayOfIds = [1, 4, 5];
var allObjects = [{"Id":"1", "name":"aa"},{"Id":"2", "name":"bb"} ,{"Id":"3", "name":"cc"} ,{"Id":"4", "name":"dd"}, {"Id":"5", "name":"ee"}, {"Id":"6", "name":"ff"}, {"Id":"7", "name":"gg"}, {"Id":"8", "name":"hh"}, {"Id":"9", "name":"ii"}];
The result would equal:
[{"Id":"1", "name":"aa"}, {"Id":"4", "name":"dd"}, {"Id":"5", "name":"ee"}]
So far, I can only use the following to extract an individual object:
var result = $.grep(arrayOfIds, function(e) { return e.Id == 3; });
I feel as though the answer might be achieved by amending the above $.grep query somehow but can't figure it out.
You don't need jQuery for this. You can use Array.prototype.filter() to filter allObjects and Array.prototype.includes() to check if the objects Id property is in arrayOfIds:
allObjects.filter(x=> arrayOfIds.includes(Number(x.Id)))
See demo on JS Bin.
Best is you transform the array to an object itself:
function atoo(a)
{
var i, obj;
obj = {};
for (i = 0; i < a.length; i++)
{
obj[a[i].Id] = a[i];
}
return obj;
}
You can now access all items in the array through the object by simply addressing them as an index:
obj["4"]
returns the correct object that is also stored in the array under a[3].
There is no jQuery involved which should be considered a feature because it is a general solution to all kinds of these problems.
Using a filter (as in Array.prototype.filter()) is easier to write but also incurs in performance problems when you access the items very often or the array is very large. The above solution relies on the internal implementation of the object referencing which is as fast as you can wish for.
You can use filter() method like following.
var arrayOfIds = [1, 4, 5];
var allObjects = [{ "Id": "1", "name": "aa" }, { "Id": "2", "name": "bb" }, { "Id": "3", "name": "cc" }, { "Id": "4", "name": "dd" }, { "Id": "5", "name": "ee" }, { "Id": "6", "name": "ff" }, { "Id": "7", "name": "gg" }, { "Id": "8", "name": "hh" }, { "Id": "9", "name": "ii" }];
var result = $(allObjects).filter(function() { return arrayOfIds.indexOf(+this.Id) > -1 }).get();