Reputation: 663
I have this first array, at the end of each item it has numerical value.
const arr = ["abc#1","def#2","z#1", "z#2"]
I have to map it with below array
const arrObj = [{
name: 'abc'
},{
name: 'def'
},{
name: 'z'
}]
to populate a new property value that has boolean in array
result = [{
name: 'abc',
value: [true, false]
},{
name: 'def',
value: [false, true]
},{
name: 'z',
value: [true, true]
}]
I'm stuck at doing multiple iteration but failed to produce above result.
const arr = ["abc#1","def#2","z#1", "z#2"]
let arrObj = [{
name: 'abc'
},{
name: 'def'
},{
name: 'z'
}]
const raw = arr.map(o => o.split('#')[0])
const key = arr.map(o => o.split('#')[1])
arrObj = arrObj.map(o => {
console.log('raw', raw)
if(raw.includes(o.name)) {
console.log('key', key)
console.log(o.name)
}
return {
...o,
value: []
}
})
Upvotes: 1
Views: 838
Reputation: 15442
Try this (UPDATED) solution:
const arr = ['abc#1', 'def#2', 'z#1', 'z#2', 'anotherName#4'];
const arrObj = [
{ name: 'abc' },
{ name: 'def' },
{ name: 'z' },
{ name: 'anotherName' }
];
// find min and max IDs
let minId;
let maxId;
arr.forEach(str => {
const id = +str.split('#')[1];
minId = typeof minId === 'undefined' || id < minId ? id : minId;
maxId = typeof maxId === 'undefined' || id > maxId ? id : maxId;
});
// build array of integers staring from minId to maxId including
const arrSize = maxId - minId + 1;
const booleanArr = Array.from(Array(arrSize)).map((_, i) => minId + i);
const arrMap = arr.reduce((res, curr) => ({
...res,
[curr]: 1
}), {});
const result = arrObj.map(({name}) => ({
name,
value: booleanArr.map(i => Boolean(arrMap[`${name}#${i}`]))
}));
console.log(result);
Upvotes: 0
Reputation: 43880
Add the following to each Object of the Array of Objects (objArray
):
objArray.forEach(object => object.value = [false, false]);
// ex. value: [false, false]
Then .split()
each String of the Array of Strings (strArray
) at the hash #
let subArray = string.split('#');
// ex. ["abc", "1"]
Convert the second string into a real index number. Note: this step is unnecessary if the strings were properly numbered -- ex. const strArray = ["abc#0", "def#1", ...]
let index = Number(subArray[1]) - 1;
Iterate through objArray
again and set each element within sub-array value
to true
according to matching object.name
and subArray[0]
and the corresponding index
number.
object.value[index] = true;
Details are also commented in demo
const strArray = ["abc#1", "def#2", "z#1", "z#2"];
let objArray = [{
name: 'abc'
}, {
name: 'def'
}, {
name: 'z'
}];
/*
Assign each object in objArray defaults to:
value: [false, false]
*/
objArray.forEach(object => object.value = [false, false]);
// Uncomment line below to view in console
/*
console.log(`~~~~~~~ objArray - initial state ~~~~~~~`);
console.log(JSON.stringify(objArray));
console.log(`~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~`);
console.log(`~~~~~~~ Sub-arrays from strArray ~~~~~~~`);
*/
for (let string of strArray) {
/*
Convert each string of strArray to a subArray:
ex. ["abc", "1"]
*/
let subArray = string.split('#');
// Convert the second string into a real index number
let index = Number(subArray[1]) - 1;
for (let object of objArray) {
/*
if object name matches the first string of a subArray...
Change the object value to true at the index previously defined
*/
if (object.name === subArray[0]) {
object.value[index] = true;
}
}
// Uncomment line below to view in console
//console.log(JSON.stringify(`['${subArray[0]}', '${subArray[1]}'] --> object.value index: ${index}`));
}
console.log(`~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~`);
console.log(`~~~~~~~~ objArray - final state ~~~~~~~~`);
console.log(JSON.stringify(objArray));
console.log(`~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~`);
for...of
LoopsNote: this is not directly related to answer. This is a reply to a comment below:
but you can't have index in
for...of
– user3106579
Refer to this example of the MDN section on .entries()
method.
const paragraphs = [...document.querySelectorAll('p')];
for (let [index, paragraph] of paragraphs.entries()) {
if (index % 2 !== 0) {
paragraph.style.color = 'tomato';
}
}
paragraphs.forEach((paragraph, index) => {
if (index % 2 === 0) {
paragraph.style.color = 'blue';
}
});
for (let i = 0; i < paragraphs.length; i++) {
if (i % 2 !== 0) {
paragraphs[i].style.backgroundColor = '#000';
}
}
*>* {
margin-left: 15px
}
p {
width: max-content;
margin-left: 30px
}
main,
h1,
section,
h2,
article,
h3 {
margin-top: -40px: margin-bottom: -40px;
}
.as-console-wrapper {
width: 350px;
min-height: 100%;
margin-left: 45%;
}
<main>
<h1>Main</h1>
<section>
<h2>Section A</h2>
<p>Paragraph aa</p>
<p>Paragraph ab</p>
<article>
<h3>Article A1</h3>
<p>Paragraph A1a</p>
<p>Paragraph A1b</p>
<p>Paragraph A1c</p>
</article>
<p>Paragraph ac</p>
<article>
<h3>Article A2</h3>
<p>Paragraph A2a</p>
<p>Paragraph A2b</p>
</article>
<p>Paragraph ad</p>
</section>
<section>
<h2>Section B</h2>
<p>Paragraph ba</p>
<article>
<h3>Article B1</h3>
<p>Paragraph B1a</p>
<p>Paragraph B1b</p>
<p>Paragraph B1c</p>
<p>Paragraph B1d</p>
</article>
<p>Paragraph bb</p>
<p>Paragraph bc</p>
</section>
</main>
Upvotes: 1
Reputation: 2974
You could do it this way:
const arr = ["abc#1","def#2","z#1", "z#2", "anotherName#4"]
const boolLength = arr.reduce((r, x) => {
const [a, b] = x.split('#');
return +b > r ? b : r
}, 0);
const tempObject = arr.reduce((r, x) => {
const [a, b] = x.split('#');
const array = r[a] || Array.from({length: boolLength}, (x, i) => false)
array[b - 1] = true;
return {
...r,
[a]: array
};
}, {});
const result = Object.keys(tempObject).reduce((r, x) => [
...r,
{
name: x,
value: tempObject[x]
}
], []);
console.log(result);
First, store in boolLength
the boolean array max lenght. Then store ìn tempObject
an object to prevent repeating name
properties. And last, in result
compose the array.
Upvotes: 0