I have an array like this :
const arr = [{name: "some", category: "Cat1"}, {name: "else", category: "Cat2"}, {name: "stuff", category: "Cat2"}]
I want to create a new array that only have category without pairs like that :
const newArr =[Cat1, Cat2]
and then map over it to render into my JSX Element. I try a lot of stuff but nothing worked Thanks for your help.
Using set object approach is the best approach. As it is already mentioned here I am going to show the other approaches.
Using Object:
You could use Array.prototype.forEach() method with Nullish coalescing operator (??) to do your job.
const arr = [
{ name: 'some', category: 'Cat1' },
{ name: 'else', category: 'Cat2' },
{ name: 'stuff', category: 'Cat2' },
];
const ret = {};
arr.forEach((x) => {
ret[x.category] = ret[x.category] ?? x.category;
});
console.log(Object.values(ret));
Using Map Object:
Map object stores key value pairs with the original insertion order. Although object is similar to map object but map object performs better when you need to do a lot of additions and deletions.
const arr = [
{ name: 'some', category: 'Cat1' },
{ name: 'else', category: 'Cat2' },
{ name: 'stuff', category: 'Cat2' },
];
const map = new Map();
const ret = [];
arr.forEach((x) => {
if (!map.has(x.category)) {
map.set(x.category, true);
ret.push(x.category);
}
});
console.log(ret);
Using Array:
Array.prototype.includes() method checks if the array contains the specified element or not and returns true or false based on that.
const arr = [
{ name: 'some', category: 'Cat1' },
{ name: 'else', category: 'Cat2' },
{ name: 'stuff', category: 'Cat2' },
];
const ret = [];
arr.forEach((x) => {
if (!ret.includes(x.category)) ret.push(x.category);
});
console.log(ret);
Using Reduce Method:
Array.prototype.reduce() method runs the given function for each iteration and reduces the array to a single value.
const arr = [
{ name: 'some', category: 'Cat1' },
{ name: 'else', category: 'Cat2' },
{ name: 'stuff', category: 'Cat2' },
];
const ret = Object.values(
arr.reduce((prev, c) => {
const p = prev;
const key = c.category;
if (!p[key]) p[key] = c.category;
return p;
}, {})
);
console.log(ret);
Try this
const arr = [
{name: "some", category: "Cat1"},
{name: "else", category: "Cat2"},
{name: "stuff", category: "Cat2"}
]
const result = arr.map(a=> a.category);
console.log([...new Set(result)]);
You are looking for something like this:
const arr = [{name: "some", category: "Cat1"}, {name: "else", category: "Cat2"}, {name: "stuff", category: "Cat2"}];
console.log([...new Set(arr.map(x => x.category))]);
Related
I have a request data - array of object like below:
const requestData = [
{
name: 'Test1',
address: 'FL',
},
{
name: 'Test2',
address: 'AL',
},
{
name: 'Test3',
address: 'AK',
},
];
I want to manipulate the object properties based on the index (that mean if index 0 change name property to USER_NAME, if index 1 means change to EMP_NAME) and convert it into final object as below:
const finalResult = {
USER_NAME: 'Test1',
USER_ADDRESS: 'FL',
EMP_NAME: 'Test2',
EMP_ADDRESS: 'AL',
CUST_NAME: 'Test3',
CUST_ADDRESS: 'AK',
};
Using reduce() and an extra map array can do it
let data = [{
name: 'Test1',
address: 'FL',
},
{
name: 'Test2',
address: 'AL',
},
{
name: 'Test3',
address: 'AK',
},
]
let mdata =['USER_','EMP_','CUST_']
let result = data.reduce((a,v,i) =>{
let key = mdata[i]
a[key+'NAME'] = v.name
a[key+'ADDRESS'] = v.address
return a
},{})
console.log(result)
You could destructure and construct your final result:
const [ user, emp, cust ] = requestData;
const finalResult = {
USER_NAME: user.name,
USER_ADDRESS: user.address,
EMP_NAME: emp.name,
EMP_ADDRESS: emp.address,
CUST_NAME: cust.name,
CUST_ADDRESS: cust.address
};
Alternatively, you could reduce, but the code winds up being a bit more complicated than is necessary for this particular example:
const keys = [ "USER", "EMP", "CUST" ];
const finalResult = requestData.reduce(( out, { name, address }, index ) => {
out[ `${ keys[ index ] }_NAME` ] = name;
out[ `${ keys[ index ] }_ADDRESS` ] = address;
return out;
}, {});
I have these two arrays, I want to check if the titles and keys match and then push the count from typesCount into types.
I have tried to do a map within a map to check the values against each other and produce a new array but it has not worked.
const types = [
{
title: 'House',
slug: 'house',
count: 0,
},
{
title: 'Car',
slug: 'car',
count: 0,
},
{
title: 'Bike',
slug 'bike',
count: 0,
},
];
const typesCount = [
{
key: 'House',
count: '11',
},
{
key: 'Bike',
count: '22',
},
];
What I've tried so far
const checkForCount = typesCount.map( x => ({
types.map( y => ({
title: y.title,
slug: y.slug,
count: y.title === x.key : x.count ? y.count,
}));
}));
This can be done by using map and find like below
const types = [{title:'House',slug:'house',count:0,},{title:'Car',slug:'car',count:0,},{title:'Bike',slug:'bike',count:0,},];
const typesCount = [{key:'House',count:'11',},{key:'Bike',count:'22',},];
//Loop through the actual array
const res = types.map(type => ({
...type,
//find if the object is present in counts array else use `{}`
count:(typesCount.find(tCount => tCount.key === type.title) || {}).count || type.count
}))
console.log(res)
This can also be done in another way by using reduce and map like below
const types = [{title:'House',slug:'house',count:0,},{title:'Car',slug:'car',count:0,},{title:'Bike',slug:'bike',count:0,},];
const typesCount = [{key:'House',count:'11',},{key:'Bike',count:'22',},];
//use reduce to format the counts like {House:"11",Bike:"22"}. This will be used while updateing the counts in the actual data
const formattedCounts = typesCount.reduce((res, obj) => {
res[obj.key] = obj.count;
return res
}, {})
const result = types.map(type => ({
...type,
//getting the count from formattedCounts object
count: formattedCounts[type.title] || type.count
}))
console.log(result)
Hope this helps.
Please try the following solution
const types = [
{
title: "House",
slug: "house",
count: 0,
},
{
title: "Car",
slug: "car",
count: 0,
},
{
title: "Bike",
slug: "bike",
count: 0,
},
];
const typesCount = [
{
key: "House",
count: "11",
},
{
key: "Bike",
count: "22",
},
];
const output = types.reduce((previousValue, currentValue) => {
const entry = typesCount.find(({ key }) => key === currentValue.title);
if (entry) {
currentValue = { ...currentValue, count: entry.count };
}
previousValue = [...previousValue, currentValue];
return previousValue;
}, []);
console.log(output);
See
Array.prototype.reduce()
You can make a Map of keys and counts from your typesCount, which looks something like so:
{
House => 11,
Bike => 22
}
You can then use .map() on your types array, where, for each object, you use the spread syntax to spread the object properties into a new object literal. You can then update the count property to be one from the map you made if it exists, if it doesn't you can default the value to the current count value of the current object.
See example below:
const types = [ { title: 'House', slug: 'house', count: 0, }, { title: 'Car', slug: 'car', count: 0, }, { title: 'Bike', slug: 'bike', count: 0, }, ];
const typesCount = [ { key: 'House', count: '11', }, { key: 'Bike', count: '22', }, ];
const counts = new Map(typesCount.map(({key, count}) => [key, count]));
const res = types.map(o => ({...o, count: counts.get(o.title) || o.count}));
console.log(res);
I have an array of objects
let myArray = [
{
id: 'first',
name: 'john',
},
{
id: 'second',
name: 'Emmy',
},
{
id: 'third',
name: 'Lazarus',
}
]
and an array
let sorter = ['second', 'third', 'first']
I would like to use lodash sorting method to sort my objects according to their position in sorter.
So that the output would be
let mySortedArray = [
{
id: 'second',
name: 'Emmy',
},
{
id: 'third',
name: 'Lazarus',
},
{
id: 'first',
name: 'john',
}
]
Is it possible to do so?
You can achieve this by using map and find:
let myArray = [
{
id: "first",
name: "john"
},
{
id: "second",
name: "Emmy"
},
{
id: "third",
name: "Lazarus"
}
];
let sorter = ["second", "third", "first"];
let mySortedArray = sorter.map(x => myArray.find(y => y.id === x));
console.log(mySortedArray);
Using lodash you can use _.sortBy
let myArray = [
{
id: 'first',
name: 'john',
},
{
id: 'second',
name: 'Emmy',
},
{
id: 'third',
name: 'Lazarus',
}
]
let sorter = ['second', 'third', 'first']
console.log(_.sortBy(myArray,(i) => {return sorter.indexOf(i.id)}))
.as-console-wrapper { max-height: 100% !important; top: 0; }
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/2.4.1/lodash.min.js"></script>
If you want to sort the array in-place, you don't need Lodash, you can easily do it with vanilla JavaScript
let myArray = [
{
id: 'first',
name: 'john',
},
{
id: 'second',
name: 'Emmy',
},
{
id: 'third',
name: 'Lazarus',
}
]
let sorter = ['second', 'third', 'first']
//create a lookup table (map) to save looking through the array
const sortLookup = new Map();
//populate with element as key - index as value
sorter.forEach((id, index) => sortLookup.set(id, index));
//sort using the indexes of sorter
myArray.sort((a, b) => sortLookup.get(a.id) - sortLookup.get(b.id))
console.log(myArray)
This is using a Map but the same can easily be accomplished with a plain JavaScript Object {}. You don't even need to pre-compute the lookup myArray.sort((a, b) => sorter.indexOf(a.id) - sorter.indexOf(b.id)) would give the exact same output but it would mean that instead of traversing sorter once for a complexity of O(n), you potentially have O(n^m)or O(n^n) (if both arrays are the same length)
Since you have an index array in the case of the sorter you can _.keyBy the main array and then use the sorter to access by index:
let myArray = [ { id: 'first', name: 'john', }, { id: 'second', name: 'Emmy', }, { id: 'third', name: 'Lazarus', } ]
let sorter = ['second', 'third', 'first']
const idMap = _.keyBy(myArray, 'id')
const result = _.map(sorter, x => idMap[x])
console.log(result)
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.11/lodash.min.js"></script>
This should perform better since you only do the idMap once and then access it by index.
I have a kids object that looks like the following:
const kids = {
name: 'john',
extra: {
city: 'London',
hobbies: [
{
id: 'football',
team: 'ABC',
},
{
id: 'basketball',
team: 'DEF',
},
],
},
};
and i have the following object that contains all sports and extra info for each.
const sports = [
{
name: 'volleyball',
coach: 'tom',
},
{
name: 'waterpolo',
coach: 'jack',
},
{
name: 'swimming',
coach: 'kate',
},
{
name: 'football',
coach: 'sara',
},
];
I want to get the list of all ids in the hobbies array and go through each of the sports items in the sports array, and found, add an extra field to that object available and give a value of true, so the result will look like:
const result = [
{
name: 'volleyball',
coach: 'tom',
},
{
name: 'waterpolo',
coach: 'jack',
},
{
name: 'swimming',
coach: 'kate',
},
{
name: 'football',
coach: 'sara',
available: true
},
];
by the way, here is my attempt:
const result = kids.extra.hobbies.map(a => a.id);
for (var key in sports) {
console.log(sports[key].name);
const foundIndex = result.indexOf(sports[key].name);
if ( foundIndex > -1) {
sports[key].available = true;
}
}
console.log(sports)
but this is too long... i am looking one liner looking code and robust logic.
This can be done many ways; however, an easy was is to divide the problem into two steps:
We can first flatten the kid's hobbies into an array by using the Array.map() function:
const hobbies = kids.extra.hobbies.map(hobby => hobby.id);
Then, we can iterate through the sports array and add an active property to any object which is present in the new hobbies array:
const result = sports.map(sport => {
if (hobbies.indexOf(sport.name) !== -1) {
sport.available = true;
}
return sport;
})
Complete Solution
const kids = {
name: 'john',
extra: {
city: 'London',
hobbies: [{
id: 'football',
team: 'ABC',
},
{
id: 'basketball',
team: 'DEF',
},
],
},
};
const sports = [{
name: 'volleyball',
coach: 'tom',
},
{
name: 'waterpolo',
coach: 'jack',
},
{
name: 'swimming',
coach: 'kate',
},
{
name: 'football',
coach: 'sara',
},
];
const hobbies = kids.extra.hobbies.map(hobby => hobby.id);
const result = sports.map(sport => {
if (hobbies.indexOf(sport.name) !== -1) {
sport.available = true;
}
return sport;
})
console.log(result);
Firstly, I would change my data structures to objects. Any time you have a list of things with unique ids, objects will make your life much easier than arrays. With that in mind, if you must use arrays, you could do the following:
const hobbies = kids.extra.hobbies
sports.forEach(s => s.available = hobbies.some(h => h.id === s.name))
Note that this mutates the original sports object (change to map for new), and also adds false/true instead of just true.
Build an array of the found sports first, then map while checking to see if the sports object's name is in it:
const kids = {name:'john',extra:{city:'London',hobbies:[{id:'football',team:'ABC',},{id:'basketball',team:'DEF',},],},}
const sports = [{name:'volleyball',coach:'tom',},{name:'waterpolo',coach:'jack',},{name:'swimming',coach:'kate',},{name:'football',coach:'sara',},];
const sportsInHobbies = kids.extra.hobbies.map(({ id }) => id);
const result = sports.map((sportObj) => {
const available = sportsInHobbies.includes(sportObj.name);
return available ? {...sportObj, available } : { ...sportObj };
});
console.log(result);
I have an array of items that I get from API as a response body.
data = [{id: 1, category: "kitchen", name: "noodles"},
{id: 2, category: "general", name: "Wi-Fi"},
{id: 3, category: "sports", name: "Football"},]
I want to iterate over the arrays, and get the data like :
var categorized = {
kitchen: [{id: 1, category: "kitchen", name: "noodles"}],
general : [{id: 2, category: "general", name: "Wi-Fi"}],
sports : [{id: 3, category: "sports", name: "Football"}]
};
Is there any lodash methods, or any ES6 shortcuts for this ?
In answer to your question 'is there a lodash method?' Yes: https://lodash.com/docs/4.17.4#groupBy. For your specific example:
const categorized = _.groupBy(data, 'category');
Edit: You could roll your own groupBy type function with ES6 as in another example. But if you are using lodash anyway this is a whole lot cleaner.
I used array.reduce to get the structure
var data = [{
id: 1,
category: "kitchen",
name: "noodles"
}, {
id: 2,
category: "general",
name: "Wi-Fi"
}, {
id: 3,
category: "sports",
name: "Football"
}]
var newData = data.reduce(function(obj, v, i) {
obj[v.category] = obj[v.category] || [];
obj[v.category].push(v);
return obj;
}, {});
console.log(newData);
In ES6 you could so using:
var newData = data.reduce((obj, v, i)=> {
obj[v.category] = obj[v.category] || [];
obj[v.category].push(v);
return obj;
}, {});
console.log(newData);