I am wondering if there is a way to dynamically add objects to an array of objects based on a value? For example, I have an array of objects:
[
{category:A, num:5},
{category:B, num:2}
]
I want to create another array of objects where objects would be the same, but repeated based on the value of num (so 5 times for category A and 2 times for category B) :
[
{category:A, num:5, repeated:1},
{category:A, num:5, repeated:2},
{category:A, num:5, repeated:3},
{category:A, num:5, repeated:4},
{category:A, num:5, repeated:5},
{category:B, num:2, repeated:1},
{category:B, num:2, repeated:2}
]
I have tried map, forEach, for loop, but nothing worked.
I am quite new to javascript, how some one could help!
You can do this using a combination of flatMap and map:
var input = [
{category:"A", num:5},
{category:"B", num:2}
] ;
var result = input.flatMap(e => [...new Array(e.num)].map( (x,i) => ({
category:e.category,
num: e.num,
repeated: i+1
})));
console.log(result);
You could do it using flatMap -
const repeat = ({ num = 0, ...t }) =>
num === 0
? []
: [ ...repeat({ ...t, num: num - 1 }), { ...t, num, repeated: num } ]
const input =
[ { category: "A", num: 5}, { category: "B", num: 2 } ]
const output =
input.flatMap(repeat)
console.log(output)
Output -
[
{ category: "A", num: 1, repeated: 1 },
{ category: "A", num: 2, repeated: 2 },
{ category: "A", num: 3, repeated: 3 },
{ category: "A", num: 4, repeated: 4 },
{ category: "A", num: 5, repeated: 5 },
{ category: "B", num: 1, repeated: 1 },
{ category: "B", num: 2, repeated: 2 }
]
Related
I have two array of objects with no common properties:
let a = [
{id: 1},
{id: 2},
{id: 3},
];
let b = [
{day: 12},
{day: 15}
];
I want to merge the props of b into a. Initially, I tried
let m = a.map((i,x) => ({id: i.id, day: b[x].day}));
This worked just fine as long as the lengths of both the arrays were the same. But when b was shorter or a was shorter, that would result in an error
Uncaught TypeError: Cannot read properties of undefined (reading 'day')
I don't really care about the length of b, all I want is a, and if b has an element at the same index, I want that b.day.
I ended up doing this:
let a = [
{id: 1},
{id: 2},
{id: 3},
];
let b = [
{day: 12},
{day: 15}
];
let m = [];
a.forEach((i, x) => {
let item = { id: i.id };
if (b.length > x) {
item['day'] = b[x].day;
}
m.push(item);
});
console.log(m);
This works fine, but it is decidedly uncool. I know this is probably more readable, but, go with me on this one.
Is there a way to make this more ES6 friendly? Is there a shorter / more concise way of achieving this please?
You could map the properties with spreading. If value at index is undefined, it acts like an empty object.
const
a = [{ id: 1 }, { id: 2 }, { id: 3 }],
b = [{ day: 12 }, { day: 15 }],
m = a.map((o, i) => ({ ...o, ...b[i] }));
console.log(m);
.as-console-wrapper { max-height: 100% !important; top: 0; }
If I understood your question correctly.
A simple way of merging 2 arrays while also merging the objects at the same index:
let a = [{ id: 1 }, { id: 2 }, { id: 3 }];
let b = [{ day: 12 }, { day: 15 }];
let m = [];
//merge a and b together in m
m = a.map((item, index) => (b[index] ? { ...item, ...b[index] } : item));
console.log(m);
//output
m= [
{
"id": 1,
"day": 12
},
{
"id": 2,
"day": 15
},
{
"id": 3
}
]
Create a new array with the maximum length of both arrays. Loop through this array and return the objects from both a and b array.
let a = [{ id: 1 }, { id: 2 }, { id: 3 }];
let b = [{ day: 12 }, { day: 15 }];
const dummyArray = new Array(Math.max(a.length, b.length)).fill(0)
let m = dummyArray.map((_, index) => ({...a[index], ...b[index]}));
console.log(m);
I have got the following array:
let x = [
{ name: "Bad", value: 2 },
{ name: "Critical", value: 1 },
{ name: "High", value: 5 },
{ name: "Medium", value: 5 },
];
The expectation is to look for "Critical" first, if the array has it, return that, else look for "High" then look for "Medium" and so on.
You can store the priorities in an array and then loop over the array and for every priority check if there's an object and whenever an object is found, return it. If the entire priorities array is exhausted then return null (or whatever you want).
const arr = [
{ name: "Bad", value: 2 },
{ name: "Critical", value: 1 },
{ name: "High", value: 5 },
{ name: "Medium", value: 5 },
],
priorities = ["Critical", "High", "Medium", "Bad"],
search = (arr, priorities) => {
for (let p of priorities) {
const obj = arr.find(({ name }) => name === p);
if (obj) {
return obj;
}
}
return null;
};
console.log(search(arr, priorities));
You can also sort the array based on the priority.
Create a Map that stores the priorities.
Sort arr based on the priorities stored in the map.
const arr = [
{ name: "Bad", value: 2 },
{ name: "Critical", value: 1 },
{ name: "High", value: 5 },
{ name: "Medium", value: 5 },
],
priorities = new Map([
["Critical", 4],
["High", 3],
["Medium", 2],
["Bad", 1],
]),
sortedArr = [...arr].sort(
(a, b) => priorities.get(b.name) - priorities.get(a.name)
);
console.log(sortedArr);
let value = x.find(x => x.name == "Critical")
|| x.find(x => x.name == "High")
|| x.find(x => x.name == "Medium") ...
First, define the order in which you want to look for items, then use that to sort the items in the array. Lastly, find based on all the items in your sort order. The first match will be returned, since the items are sorted.
const x = [{name: 'Bad',value: 2}, {name: 'High', value: 5}, {name: 'Medium', value: 5}, {name: 'Critical', value: 1}],
order = ['Critical','High','Medium'],
//sort according to above order
output = x.sort(
({name:na},{name:nb}) =>
order.findIndex(v => v === na) - order.findIndex(v => v === nb)
)
//Now find items matching name in order
.find( ({name}) => order.includes(name) );
console.log( output );
NOTE
Since your data is already sorted in the desired order, I moved the element with name = "Critical" to the end of the array.
If the data will always be sorted according to the priority you want to find the items, then no sorting is needed.
This question already has an answer here:
Filter array of object from another array
(1 answer)
Closed 3 years ago.
I want to filter an array of objects using an array but I want the results on the basis of array index and the result should be repeated when the array index value is repeated.
const data = [{
id='1',
name:'x'
},
{
id='4',
name:'a'
},
{
id='2',
name:'y'
},
{
id='3',
name:'z'
}
]
cons idArray = [1,4,3,2,4,3,2]
I have tried following code and get the result only once
const filteredData = data.filter(arrayofObj => idArray.includes(arrayofObj.id))
console.log(filteredData)
expected output is
expected output is =
[{id = '1,name:'x'},{id='4',name:'a'},{
id='3',
name:'z'
},
{
id='2',
name:'y'
},{
id='4',
name:'a'
},
{
id='3',
name:'z'
},{
id='2',
name:'y'
}]
First convert data array into Object with id's as keys.
Second, use map method over idArray and gather objects from above object.
const data = [
{
id: "1",
name: "x"
},
{
id: "4",
name: "a"
},
{
id: "2",
name: "y"
},
{
id: "3",
name: "z"
}
];
const dataObj = data.reduce((acc, curr) => {
acc[curr.id] = { ...curr };
return acc;
}, {});
const idArray = [1, 4, 3, 2, 4, 3, 2];
const results = idArray.map(id => ({ ...dataObj[id] }));
console.log(results);
You could map with a Map.
const
data = [{ id: '1', name: 'x' }, { id: '4', name: 'a' }, { id: '2', name: 'y' }, { id: '3', name: 'z' }],
idArray = [1, 4, 3, 2, 4, 3, 2],
result = idArray.map(Map.prototype.get, new Map(data.map(o => [+o.id, o])));
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
I had a variable like that
const data = {
code: 1,
items: [
{ nickname: 1, name: [
{id : "A"},
{id : "B"}
]
},
{
nickname: 2, name: [
{id: "A"},
{id: "C"}
]
}
]
}
after that, I want to show how many characters: A:2, B:1, C:1
You can do that is following steps:
Use flatMap() on the array data.items
Inside flatMap() use map() to convert all the object to their id and return it from flatMap(). This way you will array ["A","B","A","C"]
Then use reduce() and get an object with count of all the letters.
const data = { code: 1, items: [ { nickname: 1, name: [ {id : "A"}, {id : "B"} ] }, { nickname: 2, name: [ {id: "A"}, {id: "C"} ] } ] }
const res = data.items.flatMap(x =>
x.name.map(a => a.id)
).reduce((ac,a) => (ac[a] = ac[a] + 1 || 1,ac),{});
console.log(res)
const data = {
code: 1,
items: [
{
nickname: 1,
name: [
{ id: "A" },
{ id: "B" }
]
},
{
nickname: 2,
name: [
{ id: "A" },
{ id: "C" }
]
}
]
};
const res = data.items.reduce((acc, next) => {
next.name.forEach(({ id }) => {
acc[id] = acc[id] + 1 || 1;
});
return acc;
}, {});
console.log(res);
You can do that in a single shot using reduce.
Reducing data.items will allow you to add to the accumulator (initially an empty object), the value of the currently looped name property item.
The result will be an object owning all the occurences of each encountered letter in the name property of each array.
Relevant lines explained:
data.items.reduce((acc, next) will call the reduce method on data.items. acc is the reduce accumulator (initially an empty object), next is the currently looped item of data.items.
next.name.forEach(({id}) in this line, we loop the name property of the currently looped item (data.items[n]). ({id}) is a short syntax to acquire the id property of the looped item in the foreach. It's equivalent to (item => item.id).
acc[id] = acc[id] + 1 || 1; tries to increase the property [id] of the accumulator (example: "A" of {}) by 1. If it does not exist, it sets the value to 1.
return acc; returns the accumulator.
You could iterate name and take id in a loop for assigning the count.
const
data = { code: 1, items: [{ nickname: 1, name: [{ id : "A" }, { id : "B" }] }, { nickname: 2, name: [{ id: "A" }, { id: "C" }] }] },
result = data.items.reduce(
(r, { name }) => (name.forEach(({ id }) => r[id] = (r[id] || 0 ) + 1), r),
{}
);
console.log(result);
I have the following two Javascript arrays:
const array1 = [{ id: 1}, { id: 2 }, { id: 3 }, { id: 4}];
const array2 = [{ id: 1}, { id: 3 }];
I now want a new array array3 that contains only the objects that aren't already in array2, so:
const array3 = [{ id: 2}, { id: 4 }];
I have tried the following but it returns all objects, and when I changed the condition to === it returns the objects of array2.
const array3 = array1.filter(entry1 => {
return array2.some(entry2 => entry1.id !== entry2.id);
});
Any idea? ES6 welcome
You could reverse the comparison (equal instead of unqual) and return the negated result of some.
const
array1 = [{ id: 1 }, { id: 2 }, { id: 3 }, { id: 4 }],
array2 = [{ id: 1 }, { id: 3 }],
array3 = array1.filter(entry1 => !array2.some(entry2 => entry1.id === entry2.id));
// ^ ^^^
console.log(array3);
Nina's answer is a good start but will miss any unique elements in array 2.
This extends her answer to get the unique elements from each array and then combine them:
const
array1 = [{ id: 1 }, { id: 2 }, { id: 3 }, { id: 4 }],
array2 = [{ id: 1 }, { id: 3 }, { id: 5 }],
array3 = array1.filter(entry1 => !array2.some(entry2 => entry1.id === entry2.id)),
array4 = array2.filter(entry1 => !array1.some(entry2 => entry1.id === entry2.id)),
array5 = array3.concat(array4);
console.log(array5);