I have two arrays which is an array of different animals and an array of name of animals. I want to make animal buttons and each animal buttons have its own color depending on what kind of animal they are.
I was using map functions but it didn't really worked.
export const animalColors = [
{
color: '#FF6800',
name: 'lion',
},
{
color: '#D80C18',
name: 'panda',
},
{
color: '#FF8A3D',
name: 'tiger',
},
{
color: '#02C75A',
name: 'rabbit',
},
{
color: '#608DF9',
name: 'bear',
},
{
color: '#0584F6',
name: 'elephant',
},
{
color: '#222F3E',
name: 'deer',
},
{
color: '#727272',
name: 'bird',
},
{
color: '#656598',
name: 'turtle',
},
];
const zoo = [
{ id: '1', name: 'lion' },
{ id: '2', name: 'panda' },
{ id: '3', name: 'tiger' },
{ id: '4', name: 'rabbit' },
{ id: '5', name: 'bear' },
{ id: '6', name: 'elephant' },
{ id: '7', name: 'deer' },
{ id: '8', name: 'bird' },
{ id: '9', name: 'turtle' },
]
These are the codes of typescript right below.
The data.docs is the array called zoo.
const BoardItemCard = ({ data }: BoardItemCardProps) => {
return (
<div className="BoardItemCard">
{data &&
data.docs.map((item: Item, i: number) => {
return (
<button style={{backgroundColor: ????}}>
{item.name}
</button>
)
You can use array.find() to get corresponding color:
<button style={{backgroundColor: animalColors.find(x => x.name === item.name)?.color || 'defaultColor'}}>
{item.name}
</button>
Just using the Array iteration methods built into JS is fine for this:
var result1 = [
{id:1, name:'Sandra', type:'user', username:'sandra'},
{id:2, name:'John', type:'admin', username:'johnny2'},
{id:3, name:'Peter', type:'user', username:'pete'},
{id:4, name:'Bobby', type:'user', username:'be_bob'}
];
var result2 = [
{id:2, name:'John', email:'johnny#example.com'},
{id:4, name:'Bobby', email:'bobby#example.com'}
];
var props = ['id', 'name'];
var result = result1.filter(function(o1){
// filter out (!) items in result2
return !result2.some(function(o2){
return o1.id === o2.id; // assumes unique id
});
}).map(function(o){
// use reduce to make objects with only the required properties
// and map to apply this to the filtered array as a whole
return props.reduce(function(newo, name){
newo[name] = o[name];
return newo;
}, {});
});
document.body.innerHTML = '<pre>' + JSON.stringify(result, null, 4) +
'</pre>';
Related
This question already has answers here:
Merge two array of objects based on a key
(23 answers)
Closed 4 months ago.
I have 2 different arrays, that i want to combine.
The first one looks like following:
const Cats[] = [
{ id: '1', name: 'Smiley' },
{ id: '2', name: 'Purple' },
]
the second one:
const catAges[] = [
{ id: '4', age: '13', catId: '1' },
{ id: '5', age: '4', catId: '2' },
];
and i want to combine them where id from Cats[] and catId from catAges[] are the same and have a result like following:
{ id: '4', age: '13', cat: { id: '1', name: 'Smiley' } },
{ id: '5', age: '4', cat: { id: '2', name: 'Purple' } },
i get the arrays from 2 different async functions looking like this:
const cats = [await getByCatId("1"), await getByCatId("2")];
const catsAge = await getCatsAges();
But i need help in how i combine these 2 and map them. I've tried something like this but without any success:
const all = (cats, catsAge) =>
cats.map(cats=> ({
...catsAge.find((cats) => (catsAge.catId === cats.id) && catsAge),
...cats
}));
console.log(all(cats, catsAge));
Thankful for any help in how to move forward.
const Cats = [
{ id: '1', name: 'Smiley' },
{ id: '2', name: 'Purple' },
]
const catAges = [
{ id: '4', age: '13', catId: '1' },
{ id: '5', age: '4', catId: '2' },
];
const transformed = catAges.map(item => {
const cat = Cats.find(cat => cat.id === item.catId);
if (cat) {
item.cat = cat;
delete item.catId;
}
return item;
});
console.log(transformed);
The problem with your function is just that you're re-using the cats variable too much, so in your .find comparision you're comparing an element from catsAge (as cats.id) and the catsAge array (as catsAge.catId) which is undefined.
Try this:
const all = (cats, catsAge) =>
cats.map((cat) => ({
...catsAge.find((catsAge) => catsAge.catId === cat.id),
...cat,
}));
Pro tip: Learn+Use Typescript and the compiler would catch these errors for you :)
const Cats = [
{ id: '1', name: 'Smiley' },
{ id: '2', name: 'Purple' },
]
const catAges = [
{ id: '4', age: '13', catId: '1' },
{ id: '5', age: '4', catId: '2' },
];
catAges.map(catage => {
const cat = Cats.find(c => c.id == catage.catId);
if(cat) {
delete catage.catId;
catage.cat = cat;
return catage;
}
});
let bigArray = [
{
Name: 'Alice',
children: [
{Name: 'AliceChild1', Country: 'country1'},
{Name: 'AliceChild2', Country: 'country2'}
]
},
{
Name: 'Bob',
children: [
{Name: 'BobChild1', Country: 'country3'},
{Name: 'BobChild2', Country: 'country4'}
]
},
{
Name: 'Sam',
children: [
{Name: 'SamChild1', Country: 'country5'},
{Name: 'SamChild2', Country: 'country6'}
]
},
]
I want to remove an object from array inside another array. Property Name is unique. For an example if BobChild2 is removed bigArray should return as
let bigArray = [
{
Name: 'Alice',
children: [
{Name: 'AliceChild1', Country: 'country1'},
{Name: 'AliceChild2', Country: 'country2'}
]
},
{
Name: 'Bob',
children: [
{Name: 'BobChild1', Country: 'country3'},
]
},
{
Name: 'Sam',
children: [
{Name: 'SamChild1', Country: 'country5'},
{Name: 'SamChild2', Country: 'country6'}
]
},
]
What is the best way to do this in JavaScript ?
Updated:
My answer
function removeChild(bigArray, childName) {
let copyBigArray = []
bigArray.forEach((item) => {
let Obj = {
Name: item.Name,
children: item.children.filter(c => c.Name !== childName)
}
copyBigArray.push(Obj)
})
return copyBigArray
}
Try this way:
let bigArray = [{
Name: 'Alice',
children: [{
Name: 'AliceChild1',
Country: 'country1'
},
{
Name: 'AliceChild2',
Country: 'country2'
}
]
},
{
Name: 'Bob',
children: [{
Name: 'BobChild1',
Country: 'country3'
},
{
Name: 'BobChild2',
Country: 'country4'
}
]
}
]
bigArray.forEach(function(o) {
o.children = o.children.filter(s => s.Name != 'BobChild2');
});
console.log(bigArray);
To support any nested depth you can do something like this:
function searchAndRemove(arr, query) {
for (var i = arr.length; i > 0; i--) {
if (query == arr[i].Name) {
arr.splice(i, 1);
}
}
if (arr.children) {
searchAndRemove(arr.children, query);
}
}
searchAndRemove(bigArray, 'BobChild2');
This will go through your array recursively until it finds all occurrences of BobChild2 and removes them.
Well the structure isn't optimal because it'll require iterating over 2 arrays, but I'd use filter() (documentation) something like this:
function deepFilter(array, name) {
return array.map(arr => {
if (!arr || !arr.children) {
return arr;
}
arr.children = arr.children.filter(c => c.Name !== name);
return arr;
})
}
Filter has to return a Boolean to know if the element should be returned or not.
Map has to return an element.
If you want to remove an element from the first Array once its children are empty, you could replace the map by a filter.
function deepFilter(array, name) {
return array.filter(arr => {
if (!arr || !arr.children || !arr.children.length) {
return false;
}
arr.children = arr.children.filter(c => c.Name !== name);
return arr && arr.children && arr.children.length;
})
}
--
Use them by doing:
const new = deepFilter(bigArray, 'SamChild1')
Here is an example how you could achieve it:
let bigArray = [
{
Name: 'Alice',
children: [
{Name: 'AliceChild1', Country: 'country1'},
{Name: 'AliceChild2', Country: 'country2'}
]
},
{
Name: 'Bob',
children: [
{Name: 'BobChild1', Country: 'country3'},
{Name: 'BobChild2', Country: 'country4'}
]
},
{
Name: 'Sam',
children: [
{Name: 'SamChild1', Country: 'country5'},
{Name: 'SamChild2', Country: 'country6'}
]
},
]
function filterName(name, data) {
return data.reduce((arr, item) => {
if (item.Name != name) {
if (item.children) item.children = filterName(name, item.children)
arr.push(item)
}
return arr
}, [])
}
console.log(filterName("BobChild2", bigArray));
A main loop for the initial values of the array
Another loop for children values
The first parameter is the array itself that wants to be filtered, for example: bigArray
The second parameter is the value for the filter, for example: BobChild2
The third parameter is the key for the filter, for example: Name
let bigArray = [{
Name: 'Alice',
children: [
{ Name: 'AliceChild1', Country: 'country1' },
{ Name: 'AliceChild2', Country: 'country2' }
]
},
{
Name: 'Bob',
children: [
{ Name: 'BobChild1', Country: 'country3' },
{ Name: 'BobChild2', Country: 'country4' }
]
},
{
Name: 'Sam',
children: [
{ Name: 'SamChild1', Country: 'country5' },
{ Name: 'SamChild2', Country: 'country6' }
]
},
];
function filterBigArray(array, value, filter) {
let result = [];
bigArray.forEach(person => {
let childs = [];
person.children.forEach(children => {
if (children[filter] !== value) {
childs.push(children);
}
});
result.push(childs);
});
return result;
}
let res = filterArray(bigArray, 'BobChild2', 'Name');
console.log(res);
You can also filter different keys, for example:
let res = filterBigArray(bigArray, 'country3', 'Country');
console.log(res);
I want to compare these two object array and get the same result as the annotation.
My solution is an overlaid iteration, and I haven't come up with a better solution.
const arr1 = [
{key: 'cat', name: 'john' },
{key: 'dog', name: 'james' },
{key: 'dog', name: 'kane' }
];
const arr2 = [
{kind: 'cat', sound: 'meow', size: 'small', state: 'angry' },
{kind: 'dog', sound: 'woof', size: 'big', state: 'happy' },
{kind: 'pig', sound: 'oink', size: 'medium', state: 'sad' },
];
const result = arr1.map((ar) => {
const data = arr2.find(ar2=> {
return ar.key === ar2.kind;
})
const {sound} = data;
return Object.assign(ar, {sound});
});
console.log(result);
/* result
[
{key: 'cat', sound: 'meow', name: 'john'},
{key: 'dog', sound: 'woof', name: 'james'},
{key: 'dog', sound: 'woof', name: 'kane'},
]
*/
I want to know a better solution than this.
How can I solve it? Please let me know.
I'd first create an object of soundsByAnimalName, whose keys are the animal names and values are the sounds they make, then .map the first array and just look up the animal.key property on that object:
const arr1 = [
{key: 'cat', name: 'john' },
{key: 'dog', name: 'james' },
{key: 'dog', name: 'kane' }
];
const arr2 = [
{kind: 'cat', sound: 'meow', size: 'small', state: 'angry' },
{kind: 'dog', sound: 'woof', size: 'big', state: 'happy' },
{kind: 'pig', sound: 'oink', size: 'medium', state: 'sad' },
];
const soundsByAnimalName = arr2.reduce((a, { kind, sound }) => {
a[kind] = sound;
return a;
}, {});
const result = arr1.map(
animal => ({ ...animal, sound: soundsByAnimalName[animal.key] })
);
console.log(result);
You have the right idea. If you means "better" as a shorter way to write it, here it is :
You can use the ... spread operator to add a key to the json of the first array. And use of || operator to handle the case where there is no matching values.
const arr1 = [{
key: 'cat',
name: 'john'
},
{
key: 'dog',
name: 'james'
},
{
key: 'dog',
name: 'kane'
},
{
key: 'lama',
name: 'cartman'
}
];
const arr2 = [{
kind: 'cat',
sound: 'meow',
size: 'small',
state: 'angry'
},
{
kind: 'dog',
sound: 'woof',
size: 'big',
state: 'happy'
},
{
kind: 'pig',
sound: 'oink',
size: 'medium',
state: 'sad'
},
];
const ret = arr1.map(x => {
const {
sound = '',
size = '',
} = (arr2.find(y => y.kind === x.key) || {});
return ({
...x,
sound,
size,
});
});
console.log(ret);
I've been working on this couple hours and google around, see lots of example for remove duplicate, but not combined the value. so I hope someone can help me out here.
I want to check the item.name is the same, then add the price together then push to new list array.
const items = [
{ name: 'apple', price: '10' },
{ name: 'banana', price: '1' },
{ name: 'orange', price: '2' },
{ name: 'apple', price: '5' },
{ name: 'orange', price: '2.5' },
{ name: 'banana', price: '3' },
{ name: 'strawberry', price: '7' },
{ name: 'apple', price: '12' }
]
let newItem = []
const checkItem = items.map((prev, next) => {
if (prev.name === next.name) {
return newItem.push = {
name: next.name,
value: parseInt(prev.price) + parseInt(next.price)
}
}
});
console.log(newItem)
Big thanks for the help!
This will work.You can use reduce with Find.
const items = [{
name: 'apple',
price: '10'
},
{
name: 'banana',
price: '1'
},
{
name: 'orange',
price: '2'
},
{
name: 'apple',
price: '5'
},
{
name: 'orange',
price: '2.5'
},
{
name: 'banana',
price: '3'
},
{
name: 'strawberry',
price: '7'
},
{
name: 'apple',
price: '12'
}
]
let result = items.reduce((acc, el) => {
if (acc.filter(ele => ele.name == el.name).length == 0) {
acc.push(el);
} else {
let filtered = acc.find(ele => ele.name == el.name)
filtered.price = parseFloat(filtered.price) + parseFloat(el.price);
}
return acc;
}, [])
console.log(result)
var new_array = arr.map(function callback(currentValue[, index[, array]]) {
// Return element for new_array
}[, thisArg])
The Array.prototype.map()'s callback functions first two arguments are currentValue i.e item of the array and second value is it's index, & not prev and next elements.
What you are looking for is something like this.
const items = [
{ name: "apple", price: "10" },
{ name: "banana", price: "1" },
{ name: "orange", price: "2" },
{ name: "apple", price: "5" },
{ name: "orange", price: "2.5" },
{ name: "banana", price: "3" },
{ name: "strawberry", price: "7" },
{ name: "apple", price: "12" }
];
const combine = items.reduce((acc, item) => {
if (acc[item.name] !== undefined) {
acc[item.name] += Number(item.price);
} else acc[item.name] = Number(item.price);
return acc;
}, {});
const fruitKeys = Object.keys(combine);
newItem = fruitKeys.map(item => ({ name: item, price: combine[item] }));
console.log(newItem);
I have split the solution into two steps, namely combine and reconstruction of the object so that you can clearly see what's happening.
I highly recommend you to refer the documentation for reduce method to understand its working
I have two arrays of objects:
array1 = [
{id:1, name: 'one'},
{id:4, name: 'four'}
]
array2 = [
{id:1, name: 'one'},
{id:2, name: 'two'},
{id:3, name: 'three'},
{id:5, name: 'five'},
{id:6, name: 'six'},
{id:7, name: 'seven'}
]
I would like to remove any object from array1 who's id does not exist in array2.
so my expect result would be:
array1 = [
{id:1, name:'one'}
]
Use lodash's _.intersectionBy():
var array1 = [
{id:1, name: 'one'},
{id:4, name: 'four'}
];
array2 = [
{id:1, name: 'one'},
{id:2, name: 'two'},
{id:3, name: 'three'},
{id:5, name: 'five'},
{id:6, name: 'six'},
{id:7, name: 'seven'}
];
var result = _.intersectionBy(array1, array2, 'id');
console.log(result);
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.4/lodash.min.js"></script>
A fast and readable option would be:
var referenceKeys = array2.map(function(entity) { return entity.id; });
var result = array1.filter(function(entity) {
return referenceKeys.indexOf(entity.id) !== -1;
});
But no guarantee that it's the fastest in all dimensions. (Number of repeats, length of array1, length of array2).
You could use a standard approach by using a hash table which uses just one iteration for both arrays.
var array1 = [{ id: 1, name: 'one' }, { id: 4, name: 'four' }],
array2 = [{ id: 1, name: 'one' }, { id: 2, name: 'two' }, { id: 3, name: 'three' }, { id: 5, name: 'five' }, { id: 6, name: 'six' }, { id: 7, name: 'seven' }],
hash = Object.create(null),
result;
array2.forEach(function (o) {
hash[o.id] = true;
});
result = array1.filter(function (o) {
return hash[o.id];
});
console.log(result);
You can use a Set for this:
const seenIds = array2.reduce((set, o) => set.add(o.id), new Set());
const result = array1.filter(o => seenIds.has(o.id));