I have one specific problem that I'm having difficulty Googling the answer for.
This is the code:
records.forEach(function(record){
var personID = record.id;
var personsInterest = record.interest;
console.log(personID);
console.log(personsInterest);
console.log();
}
It outputs the following:
138
death note
146
poop
138
poop
146
rick and morty
138
rick and morty
138
lil peep
145
420
I would really like the code to store the data like this
[
{
id: "138",
interests:["death note","poop","rick and morty","lil peep"]
},
{
id: "146",
interests:["poop","rick and morty"]
},
{
id: "145",
interests:["420"]
}
]
where they are ordered by the length of the interests array
This should work. Annotated in comments.
const records = [{
id: 138,
interest: 'death note'
},
{
id: 146,
interest: 'poop'
},
{
id: 138,
interest: 'poop'
},
{
id: 146,
interest: 'rick and morty'
},
{
id: 138,
interest: 'rick and morty'
},
{
id: 138,
interest: 'lil peep'
}
];
const sorted = records.reduce((all, record) => {
const person = all.find(p => p.id === record.id);
//If already exists person now contains existing person
if (person) {
person.interests.push(record.interest);
//add new interest
} else all.push({
id: record.id,
interests: [record.interest]
//creates new person object
});
return all;
}, []).sort((a, b) => b.interests.length - a.interests.length);
//sorts based on length of interest array
console.log(sorted);
To achieve expected result, use below option
Loop main arr using forEach
Created result arr
Add new object to result arr
Else push to interest array
let records = [
{
id: 138,
interests: "death note"
},
{
id: 146,
interests: "poop"
},
{
id: 138,
interests: "poop"
},
{
id: 146,
interests: "rick and morty"
},
{
id: 138,
interests: "rick and morty"
},
{
id: 138,
interests: "lil peep"
},
{
id: 145,
interests: "420"
}
];
let result = [];
records.forEach(record => {
if (result.filter(item => item.id == record.id).length == 0) {
// check whether id exists in result array, if not push object to result array
result.push({ id: record.id, interests: [record.interests] });
} else {
//if id already exists in result array, push interest to interest array of that id
result.forEach(v => {
if (v.id == record.id) {
v.interests.push(record.interests);
}
});
}
});
console.log(result);
codepen - https://codepen.io/nagasai/pen/Pxmwjp?editors=1010
Use sort method with a suitable compareFunction to sort your array. arr.sort(compareFunction(a,b))
Sort method takes a function and sorts the elements of the array according to the return value of the function supplied. Let's call the function compareFunction(a, b).
If the return value of compareFunction(a, b) is less than 0: a comes first.
If the return value of compareFunction(a, b) is more than 0: b comes first.
If the return value of compareFunction(a, b) is 0: does nothing.
You want the element which has the higher interest.length comes first. So we can return b.interest.length - a.interest.length.
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/sort
var records = [{
id: 10,
interest: ["poop", "rick and morty"]
},
{
id: 11,
interest: ["eminem", "snoop dog"]
},
{
id: 12,
interest: ["death note", "poop", "rick and morty", "lil peep"]
},
{
id: 13,
interest: ["god of war"]
},
];
records = records.sort((a, b) => b.interest.length - a.interest.length);
console.log(records);
Related
Given the following array of objects:
let list = [
{id: 100, desc: 'Apple'},
{id: 555, desc: 'Banana'},
{id: 110, desc: 'Orange'},
{id: 120, desc: 'Strawberry'}
]
and the following:
let myObj = {
"res": {
"myId": 555,
"allIds": [
{
"subId": 100
},
{
"subId": 120
}
]
}
}
I need to filter the list array above so that it doesn't include the myId value and any of the subId values within the allIds array.
So based on this requirement after filtering, I expect to only see the following remaining value within the list array, i.e.:
let list = [
{id: 110, desc: 'Orange'}
]
as id: 110 doesn't equal myId and doesn't exist within the allIds array.
I tried the following which works for just myId:
let filteredArr = {list.filter((el) => el.id !== myObj.res.myId)}
but unsure how to also exclude/filter the subId's within the allIds array as well?
I tried the following which works for just myId:
let filteredArr = {list.filter((el) => el.id !== myObj.res.myId)}
but unsure how to also exclude/filter the subId's within the allIds array as well?
First, those {...} around list.filter(...) don't belong there. The { after a = starts an object initializer, but that's not valid content for an object initializer.
Use && ("and") and then myObj.res.allIds.every to see if the subId of every element in myObj.res.allIds is not a match for el.id:
let filteredArr = list.filter(
(el) => el.id !== myObj.res.myId && myObj.res.allIds.every(({ subId }) => subId !== el.id)
);
Live Example:
let list = [
{ id: 100, desc: "Apple" },
{ id: 555, desc: "Banana" },
{ id: 110, desc: "Orange" },
{ id: 120, desc: "Strawberry" },
];
let myObj = {
res: {
myId: 555,
allIds: [
{
subId: 100,
},
{
subId: 120,
},
],
},
};
let filteredArr = list.filter(
(el) => el.id !== myObj.res.myId && myObj.res.allIds.every(({ subId }) => subId !== el.id)
);
console.log(filteredArr);
That's assuming that myObj.res.allIds is fairly short, so it's okay to re-traverse it for (nearly) every element of list. If it's not short, you might want to create a Set containing all of the disallowed id valuse (myObj.res.myId and the subId values) first, since lookup time for the has method of a Set is guaranteed to be sublinear (whereas every will be linear):
const disallowed = new Set([
myObj.res.myId,
...myObj.res.allIds.map(({subId}) => subId),
]);
let filteredArr = list.filter((el) => !disallowed.has(el.id));
Live Example:
let list = [
{ id: 100, desc: "Apple" },
{ id: 555, desc: "Banana" },
{ id: 110, desc: "Orange" },
{ id: 120, desc: "Strawberry" },
];
let myObj = {
res: {
myId: 555,
allIds: [
{
subId: 100,
},
{
subId: 120,
},
],
},
};
const disallowed = new Set([
myObj.res.myId,
...myObj.res.allIds.map(({subId}) => subId),
]);
let filteredArr = list.filter((el) => !disallowed.has(el.id));
console.log(filteredArr);
You'll need to collate a list of ids that you want to filter out of your myObj object and simply filter the list. Something like this...
const blackList = [ myObj.res.myId, ...myObj.res.allIds.map(o => o.subId) ]
const filteredArr = list.filter(o => !blackList.includes(o.id))
console.log(filteredArr)
I have an array of objects I need to sort based on another array objects. This is the given array that needs to be sorted:
const arr1 = [
{
id: 21,
name: 'Joey',
vehicle: 'car'
},
{
id: 6,
name: 'Kevin'
vehicle: 'car'
},
{
id: 10,
name: 'Luis'
vehicle: 'van'
}
]
And this is the array that is in the proper order:
const arr2 = [
{
id: 6,
name: 'Kevin'
},
{
id: 21,
name: 'Joey'
},
{
id: 10,
name: 'Luis'
}
]
There is no specific order to arr2 its just the data that comes back from my db. I basically just need to put the ids in arr1 in the same order as thet are in arr2.
Ive tried using findIndex and sort but I am very confused
that ?
const arr1 =
[ { id: 21, name: 'Joey', vehicle: 'car' }
, { id: 6, name: 'Kevin', vehicle: 'car' }
, { id: 10, name: 'Luis', vehicle: 'van' }
]
const arr2 =
[ { id: 6, name: 'Kevin' }
, { id: 21, name: 'Joey' }
, { id: 10, name: 'Luis' }
]
// Arr1 ordered..
const arr1_ord = arr2.map(a2=> arr1.find(x=>x.id===a2.id))
console.log( arr1_ord )
.as-console-wrapper {max-height: 100%!important;top:0}
Also, if there are only 2 items in arr2 I still want those elements that are missing to be at the end of the sorted arr1. Would this solve that?
I add add another case : arr2 element doesn't have a arr1 same id
const arr1 =
[ { id: 21, name: 'Joey', vehicle: 'car' }
, { id: 6, name: 'Kevin', vehicle: 'car' }
, { id: 12, name: 'George', vehicle: 'carriage' } // not in arr2
, { id: 10, name: 'Luis', vehicle: 'van' }
]
const arr2 =
[ { id: 6, name: 'Kevin' }
, { id: 21, name: 'Joey' }
, { id: 88, name: 'none' } // not in arr1
, { id: 10, name: 'Luis' }
]
// Arr1 ordered..
const arr1_ord = arr2.reduce((res, {id},i,{[i+1]:next})=>
{
let a1 = arr1.find(x=>x.id===id)
if (a1) res.push(a1) // if exist in arr1
if (next) return res
else return [...res, arr1.filter(r=>!res.some(z=>z.id===r.id))] // add the missing elements
},[])
console.log( arr1_ord )
.as-console-wrapper {max-height: 100%!important;top:0}
Array.prototype.sort can take in a custom comparison function to sort however you'd like it to.
The function takes in two arguments (firstValue, secondValue)
If that function returns a positive value, then secondValue goes before the firstValue, if it's 0 or negative, then firstValue is sorted before secondValue. First/second value are from the array you are sorting. In your case, you are sorting based on a different array, but that is fine since you can do that in your function.
You can do:
arr1.sort((firstValue, secondValue) => {
return findIdInArr2(firstValue.id) - findIdInArr2(secondValue.id);
});
Where you would have to define findIdInArr2 to find the index in arr2, and you can use Array.prototype.findIndex to solve that problem. Where findIndex similarly takes in a function to find the index of something in an array.
function findIdInArr2(id) {
const foundIndex = arr2.findIndex(function(obj) {
return obj.id === id;
});
// If not found, this will be -1. But that would sort all
// unfound objects at the beginning of the array.
// To place these objects at the end of the array, it needs to
// return a number higher than the rest. So return infinity.
return (foundIndex === -1) ? Infinity : foundIndex;
}
note: findIndex is not available in IE, so you'd need to add a polyfill if you are planning on supporting IE.
i have array like this structure and want push some Non-duplicate objects
[
{
applicationNumber: "2",
id: "8cca5572-7dba-49de-971b-c81f77f221de",
country: 23,
totalPrice: 36
},
{
applicationNumber: "3",
id: "8cca5572-33333-49de-971b-c81f77f221de",
country: 1,
totalPrice: 2
}
]
i want to search on this array before push any other object on it to check existing object and after that if is not any existing object, push new object or if existing update that object only. how can i do this thing?
Try to create a function called addToArray that takes the original array and the new object to add as parameters, inside it find the index of that object of it already exist override it else push it at the end :
let arr = [{
id: 1,
country: 45
},
{
id: 2,
country: 23
},
{
id: 3,
country: 75
},
{
id: 4,
country: 39
}
]
function addToArray(ar, val) {
let index = ar.findIndex(item => item.id === val.id);
(index >= 0) ? ar[index] = val:ar.push(val)
}
console.log('before :',arr)
addToArray(arr, {
id: 2,
country: 86
})
console.log('after : ',arr)
You could use the ES6 Array.findIndex() function. Like so:
let sampleArray = [
{
applicationNumber: "2",
id: "8cca5572-7dba-49de-971b-c81f77f221de",
country: 23,
totalPrice: 36
},
{
applicationNumber: "3",
id: "8cca5572-33333-49de-971b-c81f77f221de",
country: 1,
totalPrice: 2,
}
];
const updateArr = newData =>
{
const existingIndex = sampleArray.findIndex(obj => obj.id === newData.id);
if (existingIndex >= 0)
sampleArray[existingIndex] = { ...sampleArray[existingIndex], ...newData };
else
sampleArray.push(newData)
}
const newData = { id: "8cca5572-33333-49de-971b-c81f77f221de", country: 67637674634 }
updateArr(newData);
console.log(sampleArray)
i use an event to run function on every change and after that use loop like below
vents.$on('newArr', (newArray) => {
let i;
for (i = 0; i < this.exportData.length; i++) {
let obj = this.exportData[i];
if (obj.id === newArray.id) {
delete this.exportData[i];
}
}
this.exportData.push(newArray);
});
i think it's simple and clear also if anyone think this way not optimize or not good tell me about that.
This code works, but I feel there must be a better way without having to use Array.find() twice.
const people = [
{ id: 0, age: 99 },
{ id: 1, age: 54 },
{ id: 2, age: 54 }
];
const roles = [
{ pId: 0, responsabilites: ['make money'] },
{ pId: 1, responsabilites: ['make money', 'complain'] },
{ pId: 4, responsabilites: ['make the world a better place', 'sarcasmm'] },
];
let roomsAndOrders = people.filter(p => {
return roles.find(r => r.pId === p.id);
});
roomsAndOrders = roomsAndOrders.map(p => {
let r = roles.find(r => r.pId === p.id);
return { ...r, ...p };
});
console.log(roomsAndOrders);
Just use one .map. Your original filter doesn't make much sense - filter filters out elements from an array that you don't want, but it doesn't change the elements. You're returning objects from your filter function, and objects are truthy, so the filter doesn't actually do anything.
Edit: Or just map the other way around - map from roles to people all at once, rather than mapping from people to roles.
const people = [
{ id: 0, age: 99 },
{ id: 1, age: 54 },
{ id: 2, age: 54 }
];
const roles = [
{ pId: 0, responsabilites: ['make money'] },
{ pId: 1, responsabilites: ['make money', 'complain'] },
];
const roomsAndOrders = roles.map(role => {
const person = people.find(({ id }) => role.pId === id);
return { ...role, ...person };
});
console.log(roomsAndOrders);
To only include objects whose IDs are in both arrays, you will have to use .reduce instead, since map always returns the same number of elements as in the original array:
const people = [
{ id: 0, age: 99 },
{ id: 1, age: 54 },
{ id: 2, age: 54 }
];
const roles = [
{ pId: 0, responsabilites: ['make money'] },
{ pId: 1, responsabilites: ['make money', 'complain'] },
{ pId: 4, responsabilites: ['make the world a better place', 'sarcasmm'] },
];
const roomsAndOrders = roles.reduce((accum, role) => {
const person = people.find(({ id }) => role.pId === id);
if (person) accum.push({ ...role, ...person });
return accum;
}, []);
console.log(roomsAndOrders);
You could do this in O(n) using a hashtable:
const result = [], hash = {};
for(const person of people)
result.push(hash[person.id] = {...person});
for(const role of roles)
if(hash[role.pId])
Object.assign(hash[role.pId], role);
I have 2 arrays of objects, they each have an id in common. I need a property from objects of array 2 added to objects array 1, if they have matching ids.
Array 1:
[
{
id: 1,
name: tom,
age: 24
},
{
id: 2,
name: tim,
age: 25
},
{
id: 3,
name: jack,
age: 24
},
]
Array 2:
[
{
id: 1,
gender: male,
eyeColour: blue,
weight: 150
},
{
id: 2,
gender: male,
eyeColour: green,
weight: 175
},
{
id: 3,
gender: male,
eyeColour: hazel,
weight: 200
},
]
Desired Outcome:
[
{
id: 1,
name: tom,
age: 24,
eyeColour: blue,
},
{
id: 2,
name: tim,
age: 25,
eyeColour: green,
},
{
id: 3,
name: jack,
age: 24,
eyeColour: hazel,
},
]
I tried using lodash _.merge function but then I end up with all properties into one array, when I only want eyeColour added.
Lodash remains a highly useful bag of utilities, but with the advent of ES6 some of its use cases are less compelling.
For each object (person) in the first array, find the object in the second array with matching ID (see function findPerson). Then merge the two.
function update(array1, array2) {
var findPerson = id => array2.find(person => person.id === id);
array1.forEach(person => Object.assign(person, findPerson(person.id));
}
For non-ES6 environments, rewrite arrow functions using traditional syntax. If Array#find is not available, write your own or use some equivalent. For Object.assign, if you prefer use your own equivalent such as _.extend.
This will merge all properties from array2 into array1. To only merge eyeColour:
function update(array1, array2) {
var findPerson = id => array2.find(person => person.id === id);
array1.forEach(person => {
var person2 = findPerson(person.id));
var {eyeColour} = person2;
Object.assign(person, {eyeColour});
});
}
Just noticed Paul answered while I was working on my answer but I'll add my very similar code anyway:
var getEyeColour = function (el) { return _.pick(el, 'eyeColour'); }
var out = _.merge(arr1, _.map(arr2, getEyeColour));
DEMO
You can use pick to get only the properties you want before merging:
var result = _.merge( arr1, _.map( arr2, function( obj ) {
return _.pick( obj, 'id', 'eyeColour' );
}));
A solution in plain Javascript
This is a more generic solution for merging two arrays which have different properties to union in one object with a common key and some properties to add.
var array1 = [{ id: 1, name: 'tom', age: 24 }, { id: 2, name: 'tim', age: 25 }, { id: 3, name: 'jack', age: 24 }, ],
array2 = [{ id: 1, gender: 'male', eyeColour: 'blue', weight: 150 }, { id: 2, gender: 'male', eyeColour: 'green', weight: 175 }, { id: 3, gender: 'male', eyeColour: 'hazel', weight: 200 }, ];
function merge(a, b, id, keys) {
var array = [], object = {};
function m(c) {
if (!object[c[id]]) {
object[c[id]] = {};
object[c[id]][id] = c[id];
array.push(object[c[id]]);
}
keys.forEach(function (k) {
if (k in c) {
object[c[id]][k] = c[k];
}
});
}
a.forEach(m);
b.forEach(m);
return array;
}
document.write('<pre>' + JSON.stringify(merge(array1, array2, 'id', ['name', 'age', 'eyeColour']), 0, 4) + '</pre>');
I was looking for the same, but I want to match Id before merging
And in my case, second array may have different number of items, finally I came with this:
var out = arr1.map(x => {
return { ...x, eyeColour: arr2.find(y => x.id === y.id)?.eyeColour }
});