I have the following code:
var a = [
{id:16, name:"product",productCount:1},
{id:17, name:"clothes",productCount:1},
]
var b = [
{id:1, parentId:16, name:"phone"},
{id:2, parentId:17, name:"coat"},
{id:3, parentId:16, name:"mac"},
{id:4, parentId:16, name:"apple"},
]
I tried the following:
According to the condition,Let b be a subarray of a
let result = []
a.forEach( ( item ,index)=>{
if(b[index].parentId === item.id){
result.push(item);
result[index].childAs=[];
result[index].childAs.push(b[index]);
}
})
I don't get what I want,
I expect results:
var a = [
{id:16, name:"product",productCount:1, childAs:[
{id:1, parentId:16, name:"phone"},
{id:3 ,parentId:16, name:"mac"},
{id:4, parentId:16, name:"apple"},
]
},
{id:17, name:"clothes",productCount:1, childAs:[{id:2, parentId:17, name:"coat"}]}
]
Update desired results:
What should I do if I change the result to this?
var result =
[
{label:'a name value',value:"a id value",
children:[{label:"b name value",value:"b parentId value"}]
},
...
]
Can you help me?
You can use forEach with find - for each item in b, check if the parentId exists as an id in a. If there's an item check if there's a children prop. If there is, push the element to it, if there isn't, create a new array with the element. If there is no item, carry on the loop:
var a = [
{id:16, name:"product",productCount:1},
{id:17, name:"clothes",productCount:1},
]
var b = [
{id:1, parentId:16, name:"phone"},
{id:2, parentId:17, name:"coat"},
{id:3, parentId:16, name:"mac"},
{id:4, parentId:16, name:"apple"},
]
b.forEach(o => {
const item = a.find(({id}) => id === o.parentId)
item && item.children ? item.children.push(o) : item.children = [o]
})
console.log(a)
A more efficient way to write this would be to construct a map first, instead of calling find on every loop:
var a = [{id:16, name:"product",productCount:1},{id:17, name:"clothes",productCount:1}]
var b = [{id:1, parentId:16, name:"phone"},{id:2, parentId:17, name:"coat"},{id:3, parentId:16, name:"mac"},{id:4, parentId:16, name:"apple"}]
const map = new Map(a.map(({id}, i) => [id, i]))
b.forEach(o => {
const i = map.get(o.parentId)
i !== undefined && a[i].children ? a[i].children.push(o) : a[i].children = [o]
})
console.log(a)
We use reduce to create a new array.
We construct new objects by taking the current object from array a and adding a new key to it. The new key is the result of applying filter to array 'b', where we selected the ones that match our current object's id (from array 'a').
var a = [{id:16,name:"product",productCount:1},{id:17,name:"clothes",productCount:1},]
var b = [{id:1,parentId:16,name:"phone"},{id:2,parentId:17,name:"coat"},{id:3,parentId:16,name:"mac"},{id:4,parentId:16,name:"apple"},];
function childToParentMerge(ar1, ar2) {
return ar1.reduce((a,c) => (a.push({...c, childAs: ar2.filter(o => o.parentId == c.id)}),a),[])
}
console.log(childToParentMerge(a,b))
The following is conform with the updated description:
var a = [{id:16,name:"product",productCount:1},{id:17,name:"clothes",productCount:1},]
var b = [{id:1,parentId:16,name:"phone"},{id:2,parentId:17,name:"coat"},{id:3,parentId:16,name:"mac"},{id:4,parentId:16,name:"apple"},];
function childToParentMerge(ar1, ar2) {
return ar1.reduce((a,c) => (a.push({label: c.name, value: c.id, childAs:
ar2.reduce((ac,oc) =>
(oc.parentId == c.id && ac.push({label: oc.name, value: oc.parentId}),ac),[])
}),a),[])
}
console.log(childToParentMerge(a,b))
You can use map and filter
map over array a, for each element filter the values form b with parentId same as id of current element
Build a new object with current element along with the childAs property
var a = [{id:16, name:"product",productCount:1},{id:17, name:"clothes",productCount:1}]
var b = [{id:1, parentId:16, name:"phone"},{id:2, parentId:17, name:"coat"},{id:3, parentId:16, name:"mac"},{id:4, parentId:16, name:"apple"}]
let final = a.map(inp => {
let childs = b.filter(({parentId})=> parentId === inp.id)
return {...inp,childAs:childs}
})
console.log(Object.values(final))
You could take a Map and push the values to the corresponding parents.
var a = [{ id: 16, name: "product", productCount: 1 }, { id: 17, name: "clothes", productCount: 1 }],
b = [{ id: 1, parentId: 16, name: "phone" }, { id: 2, parentId: 17, name: "coat" }, { id: 3, parentId: 16, name: "mac" }, { id: 4, parentId: 16, name: "apple" }],
map = a.reduce((m, o) => m.set(o.id, Object.assign({}, o, { children: [] })), new Map),
result = [...map.values()];
b.forEach(o => map.get(o.parentId).children.push(o));
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
You could group b based on parentId. Then map the a array and get the children from grouped
const a=[{id:16,name:"product",productCount:1},{id:17,name:"clothes",productCount:1},],
b=[{id:1,parentId:16,name:"phone"},{id:2,parentId:17,name:"coat"},{id:3,parentId:16,name:"mac"},{id:4,parentId:16,name:"apple"},];
const grouped = b.reduce((map, o) =>
map.set(o.parentId, (map.get(o.parentId) || []).concat(o))
, new Map)
const output = a.map(o => ({ ...o, childAs: grouped.get(o.id) || [] }))
console.log(output)
Related
I have an array containing objects in javascript / typescript.
let array = [{id:1,name:'One'}, {id:2, name:'Two'}, {id:3, name: 'Three'}]
How can I update name of the second element (with id 2) and copy the array to a new array using javascript spread (...) operator?
You can use a mix of .map and the ... spread operator
You can set the value after you've created your new array
let array = [{id:1,name:'One'}, {id:2, name:'Two'}, {id:3, name: 'Three'}];
let array2 = array.map(a => {return {...a}})
array2.find(a => a.id == 2).name = "Not Two";
console.log(array);
console.log(array2);
.as-console-wrapper { max-height: 100% !important; top: 0; }
Or you can do it in the .map
let array = [{id:1,name:'One'}, {id:2, name:'Two'}, {id:3, name: 'Three'}];
let array2 = array.map(a => {
var returnValue = {...a};
if (a.id == 2) {
returnValue.name = "Not Two";
}
return returnValue
})
console.log(array);
console.log(array2);
.as-console-wrapper { max-height: 100% !important; top: 0; }
Using Spred Operator, you can update particular array value using following method
let array = [
{ id: 1, name: "One" },
{ id: 2, name: "Two" },
{ id: 3, name: "Three" },
];
const label = "name";
const newValue = "Two Updated";
// Errow comes if index was string, so make sure it was integer
const index = 1; // second element,
const updatedArray = [
...array.slice(0, index),
{
// here update data value
...array[index],
[label]: newValue,
},
...array.slice(index + 1),
];
console.log(updatedArray);
There are a few ways to do this. I would suggest using Array.map :
let new_array = array.map(element => element.id == 2 ? {...element, name : 'New Name'} : element);
or with Object.assign :
let new_array = array.map(element => element.id == 2 ? Object.assign({}, element, {name : 'New Name'}) : element);
Map returns a new array, so you shouldn't need the array spread operator.
We can use
let array = [{id:1,name:'One'}, {id:2, name:'Two'}, {id:3, name: 'Three'}];
let array2 = [...array]
array2.find(a => a.id == 2).name = "Not Two";
console.log(array2);
You can simply use map() and change the element there.
here is the code---
array_copy = array.map((element) => {
console.log(element.id);
if (element.id === 2) {
element.name = "name changed";
}
return element;
});
console.log(array_copy);
Here the main array also gets modified, as elements inside the array are objects and it references to the same location even in the new array.
You can do it like this in map, no need for spread:
const array = [{id:1,name:'One'}, {id:2, name:'Two'}, {id:3, name: 'Three'}]
const updatedArray = array.map(a => {
if (a.id == 2) {
a.name = 'New Name';
}
return a;
});
Merging properties from filterQueryParams to selectedLaws (existing solutions did not suit me):
if (this.filterQueryParams && Object.prototype.toString.call(this.filterQueryParams) === '[object Array]') {
for (const law of this.filterQueryParams) {
if (law as Laws.LawDetail) {
const selectedLaw = this.selectedLaws.find(x => x.languageCode === law.languageCode);
if (selectedLaw) {
for (const propName of Object.keys(law)) {
selectedLaw[propName] = law[propName];
}
}
else {
this.selectedLaws.push(law);
}
}
}
}
import React,{useState} from 'react';
export function App(props) {
const[myObject,setMyObject] = useState({
"Name":"",
"Age":""
});
const[myarray, setmyarray] = useState([]);
const addItem =() =>{
setMyObject({...myObject,"Name":"Da","Age":"20"});
setmyarray([...myarray, 1]);
};
console.log(myarray);console.log(myObject);
return (
<div className='App'>
<h1>Hello React.</h1>
<h2>Start editing to see some magic happen!</h2>
<button onClick={addItem}>Add me</button>
</div>
);
}
// Log to console
console.log('Hello console')
let array = [{id:1,name:'One'}, {id:2, name:'Two'}, {id:3, name: 'Three'}];
let array2 =[...array.slice(0, 0), Object.assign({}, array[0], {
name:'new one' //change any property of idx
}),...array.slice(0 + 1)]
console.log(array);
console.log(array2);
[...array.slice(0, idx), Object.assign({}, array[idx], {
x:new_x //change any property of idx
}),...array.slice(idx + 1)]
I havve two different arrays with different property names like below
arrayA = [
{ id: 20, name: 'Jason' },
{ id: 15, name: 'Harry' },
{ id: 5, name: 'Clara' },
{ id: 9, name: 'Melonie' }
]
arrayB = [
{ courseID: 12, studentID: 20 },
{ courseID: 12, studentID: 15 }
]
I want to compare these two different arrays and remove unmatched ids from arrayA. For comparison, id field of arrayA and studentID field of arrayB matters. if these fileds aren't equal to each other, they should be removed from arrayA.
Expected is below
arrayA = [{id: 20, name: 'Jason' }, { id: 15, name: 'Harry' }]
Here is what I tried below but didn't work. Gave me empty array.
filteredElements = this.arrayA.map(e => e.id).filter(
val => this.arrayB.indexOf(val.studentID) !== -1
);
You can do that in following steps:
Use map() on arrayB and create array of courseID.
Then create a Set() from that Array
Then use filter() arrayA and check whether id of object exists in above created Set or not using Set.prototype.has()
const arrayA = [{id:20,name:'Jason'},{id:15,name:'Harry'},{id:5,name:'Clara'},{id:9,name:'Melonie'}]
const arrayB =[{courseID:12,studentID:20},{courseID:12,studentID:15}];
const ids = new Set(arrayB.map(x => x.studentID));
const res = arrayA.filter(x => ids.has(x.id));
console.log(res);
let arrayA = [{id: 20,name: 'Jason'},{id: 15,name: 'Harry'},{id: 5,name: 'Clara'},{id: 9,name: 'Melonie'}]
let arrayB = [{courseID: 12,studentID: 20},{courseID: 12,studentID: 15}];
let filtered=arrayA.filter(obj =>{ if(arrayB.find(course => course.studentID == obj.id))return true;return false;
});
console.log(filtered);
Try this:
var studentIds = arrayB.map(course => course.studentID);
var result = arrayA.filter(student => studentIds.includes(student.id));
The variable result contains your result.
Create a dictionary from courseMembers, keyed on studentID, to enable O(1) lookup.
Filter students according to the dictionary.
const students = [{id:20,name:'Jason'},{id:15,name:'Harry'},{id:5,name:'Clara'},{id:9,name:'Melonie'}]
const courseMembers = [{courseID:12,studentID:20},{courseID:12,studentID:15}]
function withCourses(students, courseMembers) {
const map = courseMembers.reduce((acc, {studentID}) =>
(acc[studentID] = true, acc), {})
return students.filter(({id}) => map[id])
}
const result = withCourses(students, courseMembers)
console.log(result) // [{ id:20, name:"Jason" },{ id:15, name:"Harry" }]
Trying to loop over two arrays and finding the codes for each, I might be missing some part. I need to construct a new array with this values, each id can be multiple times in the arrayB. Based on id in first array we have to match the id in a second array (arrayA) and get code
let arrayA=[
{"breadcrumb":{id: "abdc4051"}, type:"details"},
{"breadcrumb":{id: "abdc4052"}, type:"details"},
let arrayB=[
{"breadcrumb": {id: "abdc4051",code: "mike", length:"short"}},
{"breadcrumb": {id: "abdc4051", code: "pohan", length:"long"}}, {"breadcrumb": {id: "abdc4052", code: "junior", length:"short"}}]
let arrayC = [];
// output expected
[{"id":"abdc4051", shortLength: "mike", longLength:"pohan"}, {"id":"abdc4052", shortLength: "Junior", longLength:"-"}]
// tried this
function isBiggerThan10(element, index, array) {
return element > 10;
}
arrayA.forEach(function(element){
arrayC.push({
id:element.id,
firstName:(arrayB.find(
e => e.attributes.code==="mike")).breadCrumbs.shortLength,
lastName:(arrayB.find(
e => e.code==="pohan")).breadCrumbs.longlength
})
});
console.log(arrayC);
Here's one solution using the built in array methods. The steps are:
For each item in arrayA, perform the following:
Find all items in arrayB that have the same ID (using .filter).
Combine all those results into a single object, using default "-" for first and last name if not present (using .reduce).
Put that into the results array (handled by using .map on arrayA in the first place).
let arrayA = [
{"breadcrumb":{id: "abdc4051"}, type:"details"},
{"breadcrumb":{id: "abdc4052"}, type:"details"},
]
let arrayB = [
{"breadcrumb": {id: "abdc4051", firstName: "mike"}},
{"breadcrumb": {id: "abdc4051", lastName: "pohan"}},
{"breadcrumb": {id: "abdc4052", firstName: "junior"}},
]
// output expected
// [
// {"id":"abdc4051", firstName: "mike", lastName:"pohan"},
// {"id":"abdc4052", firstName: "Junior", lastName:"-"},
// ]
const result = arrayA.map(itemA => {
return arrayB
.filter(itemB => itemB.breadcrumb.id === itemA.breadcrumb.id)
.reduce((combo, item) => ({...combo, ...item.breadcrumb}), {firstName: "-", lastName: "-"})
});
console.log(result);
EDIT: Per edited question, you can modify the reduce function to see if the combo has firstCode set or not. If it does, then put the next code under the key lastCode, otherwise keep it as firstCode. This will base the first/last code on the order they appear in arrayB:
let arrayA = [
{"breadcrumb":{id: "abdc4051"}, type:"details"},
{"breadcrumb":{id: "abdc4052"}, type:"details"},
]
let arrayB = [
{"breadcrumb": {id: "abdc4051", code: "mike"}},
{"breadcrumb": {id: "abdc4051", code: "pohan"}},
{"breadcrumb": {id: "abdc4052", code: "junior"}},
]
// output expected
// [
// {"id":"abdc4051", firstCode: "mike", lastCode:"pohan"},
// {"id":"abdc4052", firstCode: "Junior", lastCode:"-"},
// ]
const result = arrayA.map(itemA => {
return arrayB
.filter(itemB => itemB.breadcrumb.id === itemA.breadcrumb.id)
.reduce((combo, item) => ({...combo, [combo.firstCode === "-" ? "firstCode" : "lastCode"]: item.breadcrumb.code, id: itemA.breadcrumb.id}), {firstCode: "-", lastCode: "-"})
});
console.log(result);
EDIT 2: Per second edit, you can again modify the reduce to suit your needs:
let arrayA = [
{"breadcrumb":{id: "abdc4051"}, type:"details"},
{"breadcrumb":{id: "abdc4052"}, type:"details"},
]
let arrayB = [
{"breadcrumb": {id: "abdc4051", code: "mike", length: "short"}},
{"breadcrumb": {id: "abdc4051", code: "pohan", length: "long"}},
{"breadcrumb": {id: "abdc4052", code: "junior", length: "short"}},
]
// output expected
// [
// {"id":"abdc4051", shortLength: "mike", longLength:"pohan"},
// {"id":"abdc4052", shortLength: "junior", longLength:"-"},
// ]
const result = arrayA.map(itemA => {
return arrayB
.filter(itemB => itemB.breadcrumb.id === itemA.breadcrumb.id)
.reduce((combo, item) => ({...combo, [item.breadcrumb.length + "Length"]: item.breadcrumb.code, id: itemA.breadcrumb.id}), {shortLength: "-", longLength: "-"})
});
console.log(result);
Start a chain with arrayB. Use _.map() to get the content of breadcrumb, _.groupBy() by id. Use _.pick() with the ids of arrayA to get the groups you want. Map each group to required form using _.transform():
const arrayA=[{"breadcrumb":{"id":"abdc4051"},"type":"details"},{"breadcrumb":{"id":"abdc4052"},"type":"details"}];
const arrayB=[{"breadcrumb":{"id":"abdc4051","code":"mike","length":"short"}},{"breadcrumb":{"id":"abdc4051","code":"pohan","length":"long"}},{"breadcrumb":{"id":"abdc4052","code":"junior","length":"short"}}];
const result = _(arrayB)
.map('breadcrumb') // unwrap breadcrumb
.groupBy('id')
.pick(arrayA.map((o) => _.get(o, 'breadcrumb.id'))) // get all groups that match arrayA ids
.map((g, key) => _.transform(g, (acc, v) => { // transform each group to the requested form
acc[`${v.length}Length`] = v.code;
}, { key, shortLength: '-', longLength: '-' }))
.value();
console.log(result);
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.5/lodash.min.js"></script>
What is the best way to transform an array like this:
const arr = [
{ name: 'Bob' },
{ name: 'Ben' }
{ name: 'Cole' }
{ name: 'Mary' }
{ name: 'Travis' }
]
to an object like:
const obj = {
'B': ['Bob', 'Ben'],
'C': ['Cole'],
'M': ['Mary'],
'T': ['Travis']
}
Using only vanilla JS
You can use array#reduce. Iterate through each object of your array and then extract out the first letter and add names corresponding to it.
const arr = [{name: 'Bob'}, {name: 'Ben'}, {name: 'Cole'}, {name: 'Mary'}, {name: 'Travis'}],
result = arr.reduce((r,{name}) => {
r[name[0]] = r[name[0]] || [];
r[name[0]].push(name);
return r;
},{});
console.log(result);
Vanilla JS you say? Here you go
let nil = x => x === undefined;
let empty = ([h]) => nil(h);
let first = ([h]) => h;
let last = ([h, ...t]) => empty(t) ? h : last(t);
let map = ([h, ...t], f) => nil(h) ? [] : [f(h), ...map(t, f)];
let reduce = ([h, ...t], f, i) => nil(h) ? i : reduce(t, f, f(i, h));
let tab = (a, f) => map(a, x => [x, f(x)]);
let push = (a, x) => nil(a) ? [x] : [...a, x];
let groupBy = (a, f) => _groupBy(tab(a, f));
let _groupBy = ka => reduce(ka, (g, [x, k]) => ({...g, [k]: push(g[k], x)}), {});
///
const arr = [{ name: 'Bob' },{ name: 'Ben' },{ name: 'Cole' },{ name: 'Mary' },{ name: 'Travis' }]
z = groupBy(map(arr, x => x.name), first)
console.log(z)
No built-ins!
I created an array where the key is the first letter of the name using the reduce function and restructuring the 'name' from the objects. If the key exists in the array the name is pushed (using spread operator). Else, it creates the key with only one element.
const arr = [
{ name: 'Bob' },
{ name: 'Ben' },
{ name: 'Cole' },
{ name: 'Mary' },
{ name: 'Travis' }
];
const obj = arr.reduce((res, {name})=>{
res[name[0]] = res[name[0]] ? [...res[name[0]],name] : [name];
return res;
}, {});
console.log(obj);
I think this thread is missing a non functional answer, so here it is:
const obj = {};
for(const {name} of arr)
(obj[name[0]] || (obj[name[0]] = [])).push({name});
let obj = {};
arr.forEach( e => {
const name = e.name;
if (!obj[name.charAt(0)]) obj[name.charAt(0)] = [];
obj[name.charAt(0)].push(name);
})
I'm generating a new object and adding to it news keys based in the first char of the name values (only if the key hasn't been already added).
Then, I add each value to the key that corresponds.
I have an array containing objects in javascript / typescript.
let array = [{id:1,name:'One'}, {id:2, name:'Two'}, {id:3, name: 'Three'}]
How can I update name of the second element (with id 2) and copy the array to a new array using javascript spread (...) operator?
You can use a mix of .map and the ... spread operator
You can set the value after you've created your new array
let array = [{id:1,name:'One'}, {id:2, name:'Two'}, {id:3, name: 'Three'}];
let array2 = array.map(a => {return {...a}})
array2.find(a => a.id == 2).name = "Not Two";
console.log(array);
console.log(array2);
.as-console-wrapper { max-height: 100% !important; top: 0; }
Or you can do it in the .map
let array = [{id:1,name:'One'}, {id:2, name:'Two'}, {id:3, name: 'Three'}];
let array2 = array.map(a => {
var returnValue = {...a};
if (a.id == 2) {
returnValue.name = "Not Two";
}
return returnValue
})
console.log(array);
console.log(array2);
.as-console-wrapper { max-height: 100% !important; top: 0; }
Using Spred Operator, you can update particular array value using following method
let array = [
{ id: 1, name: "One" },
{ id: 2, name: "Two" },
{ id: 3, name: "Three" },
];
const label = "name";
const newValue = "Two Updated";
// Errow comes if index was string, so make sure it was integer
const index = 1; // second element,
const updatedArray = [
...array.slice(0, index),
{
// here update data value
...array[index],
[label]: newValue,
},
...array.slice(index + 1),
];
console.log(updatedArray);
There are a few ways to do this. I would suggest using Array.map :
let new_array = array.map(element => element.id == 2 ? {...element, name : 'New Name'} : element);
or with Object.assign :
let new_array = array.map(element => element.id == 2 ? Object.assign({}, element, {name : 'New Name'}) : element);
Map returns a new array, so you shouldn't need the array spread operator.
We can use
let array = [{id:1,name:'One'}, {id:2, name:'Two'}, {id:3, name: 'Three'}];
let array2 = [...array]
array2.find(a => a.id == 2).name = "Not Two";
console.log(array2);
You can simply use map() and change the element there.
here is the code---
array_copy = array.map((element) => {
console.log(element.id);
if (element.id === 2) {
element.name = "name changed";
}
return element;
});
console.log(array_copy);
Here the main array also gets modified, as elements inside the array are objects and it references to the same location even in the new array.
You can do it like this in map, no need for spread:
const array = [{id:1,name:'One'}, {id:2, name:'Two'}, {id:3, name: 'Three'}]
const updatedArray = array.map(a => {
if (a.id == 2) {
a.name = 'New Name';
}
return a;
});
Merging properties from filterQueryParams to selectedLaws (existing solutions did not suit me):
if (this.filterQueryParams && Object.prototype.toString.call(this.filterQueryParams) === '[object Array]') {
for (const law of this.filterQueryParams) {
if (law as Laws.LawDetail) {
const selectedLaw = this.selectedLaws.find(x => x.languageCode === law.languageCode);
if (selectedLaw) {
for (const propName of Object.keys(law)) {
selectedLaw[propName] = law[propName];
}
}
else {
this.selectedLaws.push(law);
}
}
}
}
import React,{useState} from 'react';
export function App(props) {
const[myObject,setMyObject] = useState({
"Name":"",
"Age":""
});
const[myarray, setmyarray] = useState([]);
const addItem =() =>{
setMyObject({...myObject,"Name":"Da","Age":"20"});
setmyarray([...myarray, 1]);
};
console.log(myarray);console.log(myObject);
return (
<div className='App'>
<h1>Hello React.</h1>
<h2>Start editing to see some magic happen!</h2>
<button onClick={addItem}>Add me</button>
</div>
);
}
// Log to console
console.log('Hello console')
let array = [{id:1,name:'One'}, {id:2, name:'Two'}, {id:3, name: 'Three'}];
let array2 =[...array.slice(0, 0), Object.assign({}, array[0], {
name:'new one' //change any property of idx
}),...array.slice(0 + 1)]
console.log(array);
console.log(array2);
[...array.slice(0, idx), Object.assign({}, array[idx], {
x:new_x //change any property of idx
}),...array.slice(idx + 1)]