Assign First Element of Nested Array as Property of Parent Object - javascript

Assuming the following Array:
[
{id: 1234, name: "#Acme", sources:["Twitter"]},
{id: 5678, name: "#Enron", sources:["Facebook"]},
]
I want to promote sources[0] to a property value, either under sources itself or as a new key using lodash.
I've done the following:
myList = _.map(monitorList, _.partialRight(_.pick, ['id', 'name', 'sources']));
mySources = _.map(monitorList, 'sources');
I imagine I can iterate through each respective array now and map my index from mySources to the sources key in myList, however it seems like there should be a functional way using lodash to promote a nested array item to a property value.
Ideal final data structure:
[
{id: 1234, name: "#Acme", sources:"Twitter"},
{id: 5678, name: "#Enron", sources:"Facebook"},
]

With a functional ES6 approach:
const monitorList = [
{id: 1234, name: "#Acme", sources:["Twitter"]},
{id: 5678, name: "#Enron", sources:["Facebook"]},
];
var result = monitorList.map(o => Object.assign({}, o, { sources: o.sources[0] }));
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }

You can follow a simple path and use forEach to replace sources property:
var items = [{id: 1234, name: "#Acme", sources:["Twitter"]},
{id: 5678, name: "#Enron", sources:["Facebook"]}];
items.forEach((item) => item.sources = item.sources[0]);
console.log(items);
Another solution, using map, which is more functional (as it does not change items variable):
var items = [{id: 1234, name: "#Acme", sources:["Twitter"]},
{id: 5678, name: "#Enron", sources:["Facebook"]}];
var newItems = items.map((item) => Object.assign({}, item, { sources: item.sources[0] }));
console.log(newItems);

You could use map:
var array = [{id: 1234, name: "#Acme", sources:["Twitter"]},
{id: 5678, name: "#Enron", sources:["Facebook"]}];
var items = array.map(item => {
item.source = item.sources[0];
return item;
});
You could change item.source to item.sources as well if you wanted to overwrite.
Another way using some losdash methods:
var items = array.map(item => {
return _.assign({}, item, {sources: _.first(item.sources)});
});

Related

How to remap array in React [duplicate]

This question already has answers here:
How to rename properties of objects in array in javascript?
(5 answers)
Closed 4 months ago.
How to do a remapo for new objects like:
...
const inputArr = [
{id: '1', name: "test1", routeName: "somethig/something"},
{id: '2', name: "something2", routeName: "foo/bar"},
{id: '3', name: "someanothrelement", routeName: "test/test"}
]
//to =>
const resultStructureArr = [
{ id: '1', value: 'somethig/something', label: 'test1' },
{ id: '2', value: 'foo/bar', label: 'something2' },
{ id: '3', value: 'test/test', label: 'someanothrelement' },
];
...
Here is the jsfiddle
Just using map() can do it
const inputArr = [
{id: '1', name: "test1", routeName: "somethig/something"},
{id: '2', name: "something2", routeName: "foo/bar"},
{id: '3', name: "someanothrelement", routeName: "test/test"}
]
let result = inputArr.map(a => ({'id':a.id,'label':a.name,'value':a.routeName}))
console.log(result)
We can use traditional for loop for this. Where we may loop to the length of list and for each iteration we may add new object into result array using Array.prototype.push method. Secondly we are doing the same thing with foreach loop. Third I'm using Array.prototype.map method, Which creates a new result for each iteration, in our case we are returning our new object. Lastly we are using Array.prototype.reduce method, with this method we can initialize a starting value which in my case I'm using empty array, then for each iteration I'm pushing a new object in that array and returning it.
const inputArr = [
{ id: "1", name: "test1", routeName: "somethig/something" },
{ id: "2", name: "something2", routeName: "foo/bar" },
{ id: "3", name: "someanothrelement", routeName: "test/test" },
];
// Using for loop
let result = [];
for (let i = 0; i < inputArr.length; i++) {
result.push({
id: inputArr[i].id,
value: inputArr[i].routeName,
label: inputArr[i].name,
});
}
console.log(result);
result = [];
// using foreach loop
inputArr.forEach((item) => {
result.push({ id: item.id, label: item.name, value: item.routeName });
});
console.log(result);
result = [];
// using map
result = inputArr.map((item) => ({
id: item.id,
label: item.name,
value: item.routeName,
}));
console.log(result);
result = [];
// using reduce
result = inputArr.reduce((acc, curr) => {
acc.push({ id: curr.id, label: curr.name, value: curr.routeName });
return acc;
}, []);
console.log(result);

Delete multiple objects in an array by id

I have a main array of objects with each object having some key/values as well as a "id" key with 1,2,3,4,5, etc
Now I have another array representing just id's (like [2,3])
I want to use this array to delete objects from the main array...so in this case, objects from the main array having id's 2 & 3 should be deleted
While I am aware of findBy(id), I am not sure if that can be used to delete multiple objects at once.
You can use filter. In the filter callback function check if the id is also there in id array by using includes
let idArr = [1, 2]
let obj = [{
id: 1,
name: 'abc'
},
{
id: 2,
name: 'abc'
},
{
id: 3,
name: 'abc'
},
{
id: 4,
name: 'abc'
}
];
let data = obj.filter(item => !idArr.includes(item.id));
console.log(data);
console.log(obj)
using filter might work well here. you could write something like:
var newArray = oldArray.filter(object => !ids.includes(object.id))
You can do it, like this:
[2,3].forEach(key => {
delete object[key];
})
You can use filter method for this.
Ex:
let id = 2;
let list = [{
Id: 1,
Name: 'a'
}, {
Id: 2,
Name: 'b'
}, {
Id: 3,
Name: 'c'
}];
let lists = list.filter(x => {
return x.Id != id;
})
console.log(lists);
Assuming you want to delete items from the original array by entirely removing the element from the array (and you don't want to get a new array), you can take advantage of
Array.splice
let idArr = [1, 2];
let obj = [{
id: 1
},
{
id: 2
},
{
id: 3
},
{
id: 4
}
];
for (let id of idArr) {
// look for the element by its id.
const objIdRef = obj.find(i => i.id === id);
// if it actually exists, splice it.
objIdRef && obj.splice(obj.indexOf(objIdRef), 1);
}
console.log(obj);
If the obj array is big, you might want to make a map from it before processing the id array, so that the complexing is reduced to O(1) when the delete process begins.
Perhaps This is what you want:
var arr= [{id:1, name: "foo"}, {id:2, name: "bar"}, {id:3, name:"not to be deleted"}];
var idsToDelete = [1, 2];
var res = arr.map((i, idx)=>{
return arr[idx] = idsToDelete.includes(i.id)? undefined : arr[idx]
}).filter(i=>i)
console.log(res)
You can try Lodash.js functions _.forEach() and _.remove()
let valuesArr = [
{id: 1, name: "dog"},
{id: 2, name: "cat"},
{id: 3, name: "rat"},
{id: 4, name: "bat"},
{id: 5, name: "pig"},
];
let removeValFromIndex = [
{id: 2, name: "cat"},
{id: 5, name: "pig"},
];
_.forEach(removeValFromIndex, (indi) => {
_.remove(valuesArr, (item) => {
return item.id === indi.id;
});
})
console.log(valuesArr)
/*[
{id: 1, name: "dog"},
{id: 3, name: "rat"},
{id: 4, name: "bat"},
]; */
Don't forget to clone (_.clone(valuesArr) or [...valuesArr]) before mutate your array

Use lodash groupBy function to categorize objects in an array

i have an array of products that each product has a category object. I need to organize by category and include the category object. GroupBy function include only one parameter.
the array of products
const data = [
{id: 1, 'name': 'produto1', category: {id: 1, name: 'shirts', description: 'super roupa'}},
{id: 2, 'name': 'produto2', category: {id: 1, name: 'shirts', description: 'super roupa'}},
{id: 3, 'name': 'produto3', category: {id: 2, name: 'jackets', description: 'super jackets'}},
{id: 4, 'name': 'produto4', category: {id: 2, name: 'jackets', description: 'super jackets'}},
]
expected result:
[
{
category: {id: 1, name: 'clothes', description: 'super roupa'},
products:[{id:1, name: 'produt1'}, {id: 2, name: 'produto1'} ]
},
{
category: {id: 2, name: 'jackets', description: 'super jackets'},
products:[{id:3, name: 'produt3'}, {id: 4, name: 'produto4'} ]
},
]
Group by the category.id, and then map the each group to an object by taking the category from the 1st item in the group, and omitting category from all products:
const data = [{"id":1,"name":"produto1","category":{"id":1,"name":"shirts","description":"super roupa"}},{"id":2,"name":"produto2","category":{"id":1,"name":"shirts","description":"super roupa"}},{"id":3,"name":"produto3","category":{"id":2,"name":"jackets","description":"super jackets"}},{"id":4,"name":"produto4","category":{"id":2,"name":"jackets","description":"super jackets"}}]
const result = _(data)
.groupBy('category.id')
.map(group => ({
category: _.head(group).category,
products: _.map(group, o => _.omit(o, 'category'))
}))
.value()
console.log(result)
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.15/lodash.js"></script>
Or the _.flow() function equivalent with lodash/fp:
const { flow, groupBy, map, head, omit } = _
const fn = flow(
groupBy('category.id'),
map(group => ({
category: head(group).category,
products: map(omit('category'), group)
}))
)
const data = [{"id":1,"name":"produto1","category":{"id":1,"name":"shirts","description":"super roupa"}},{"id":2,"name":"produto2","category":{"id":1,"name":"shirts","description":"super roupa"}},{"id":3,"name":"produto3","category":{"id":2,"name":"jackets","description":"super jackets"}},{"id":4,"name":"produto4","category":{"id":2,"name":"jackets","description":"super jackets"}}]
const result = fn(data)
console.log(result)
<script src='https://cdn.jsdelivr.net/g/lodash#4(lodash.min.js+lodash.fp.min.js)'></script>
Here's a solution without lodash:
You could reduce the data array. Destructure the parameter to get category and rest of the properties separately. Here rest will have id and name properties. Then create an accumulator object with each unique category's id as key. Set the value to be the final objects needed in the output. If the key already exists, update it's products array. Else, add a new key to the accumulator. Then finally use Object.values() to convert this accumulator object to an array of required values
const data = [{"id":1,"name":"produto1","category":{"id":1,"name":"shirts","description":"super roupa"}},{"id":2,"name":"produto2","category":{"id":1,"name":"shirts","description":"super roupa"}},{"id":3,"name":"produto3","category":{"id":2,"name":"jackets","description":"super jackets"}},{"id":4,"name":"produto4","category":{"id":2,"name":"jackets","description":"super jackets"}}]
const merged = data.reduce((acc, { category, ...rest }) => {
acc[category.id] = acc[category.id] || { category, products: [] };
acc[category.id].products.push(rest);
return acc;
}, {})
console.log(Object.values(merged))

How to get a particular attribute from an array of array objects?

I have an Array of Arrays, and each Array consists of objects. Here is a simplified version of what I'm referring to (it is a console.log of my original array) -
Array - [Array(2), Array(3), Array(2)]
Each Array has objects in the following format (taking the first array from above) -
Array(2) -
0: {name: "test", score:40, date: "2018-09-18T00:00:00.000Z"}
1: {name: "test2", score:50 date: "2018-09-18T00:00:00.000Z"}
The other arrays are similar with the same attributes and different values.
I am trying to fetch the name attribute from each of these objects. I tried the below code - but I end up getting an undefined value:
const test1= array1.map(x=> x.values) // this gives me the array of arrays
const test2 = test1.map(function(y){return y.name})// this is my attempt to get the 'name' attribute from all of the arrays that include the objects.
What am I missing out on here? Is there a better way to get the attribute using arrow functions?
Flatten it, and map it to names or Vise versa
First flatten it, and map
const array = [[{name: 'test1'}, {name: 'test2'}], [{name: 'test3'}, {name: 'test4'}]]
var res = [].concat(...array).map(({name})=>name);
console.log(res);
Now, map it to names and then flatten
const array = [[{name: 'test1'}, {name: 'test2'}], [{name: 'test3'}, {name: 'test4'}]]
var res = [].concat(...array.map(a=>a.map(b=>b.name)))
console.log(res);
Now, In this one, certainly you can notice that we are actually mapping it in each level (we have to, no other way with first map only approach. so we can perform a reduce in place of the outer map and concat it there itself, so we can avoid the outer concat (for flatten) and inner concat will actually flatten it. Here we go:
const array = [[{name: 'test1'}, {name: 'test2'}], [{name: 'test3'}, {name: 'test4'}]]
var res = array.reduce((r, a)=>r.concat(a.map(b=>b.name)), []);
console.log(res);
/* TEST DATA */
array1 = [
{ name: 'test1', score: 40, date: '2018-09-18T00:00:00.000Z' },
];
array2 = [
{ name: 'test4', score: 50, date: '2018-09-18T00:00:00.000Z' },
{ name: 'test5', score: 40, date: '2018-09-18T00:00:00.000Z' },
];
array3 = [
{ name: 'test6', score: 50, date: '2018-09-18T00:00:00.000Z' },
{ name: 'test7', score: 50, date: '2018-09-18T00:00:00.000Z' },
{ name: 'test8', score: 40, date: '2018-09-18T00:00:00.000Z' },
{ name: 'test9', score: 50, date: '2018-09-18T00:00:00.000Z' },
];
testResults = [array1, array2, array3];
// Solution
function getListOfName(){
let names = [];
testResults.map(testResult => {
testResult.map(({name}) => {if(name) names.push(name)})
})
return names;
}
console.log("Full list of names", getListOfName());
// If you want to restrict to K names from each array
function getFirstKNamesfromArray(limit){
let names = [];
testResults.map(testResult => {
testResult.map(({name}, index) => {
if(name && (index < limit)) names.push(name)
})
})
return names
}
console.log("First 2 names from each array", getFirstKNamesfromArray(2));
Take into account that map returns an array; you iterate over it. Filter or reduce do the same.
const test1= array1.map(x=> x.values) // x doesn't have a property named "value"
//simply use forEach
array1.forEach((el) => console.log(el.name))
If you want to capture the names inside a collection:
const let container = [];
array1.forEach((el) => container.push(el.name))
A good way to better understand this iterator functions would be to first use loops and then attempt to "translate" your code into one of them.
Because in your first map x is an array, not an object. So, there is no value. You should map inner arrays then get the desired value.
const arr = [
[
{
name: "test",
score: 40,
date: "2018-09-18T00:00:00.000Z"
},
{ name: "test2", score: 50, date: "2018-09-18T00:00:00.000Z" }
],
[
{
name: "foo",
score: 40,
date: "2018-09-18T00:00:00.000Z"
},
{ name: "bar", score: 50, date: "2018-09-18T00:00:00.000Z" }
]
];
const test1 = arr
.map(x => x.map(y => y.name))
.reduce((acc, el) => [...acc, ...el], []);
console.log(test1);
This should work fine. You need to flatten the array structure and map the names.
const array = [[{name: 'test1'}, {name: 'test2'}], [{name: 'test3'}, {name: 'test4'}]]
const names = array.reduce((acc, innerArray) => {
return [...acc, ...innerArray.map(entry => entry.name)]
}, [])
console.log(names)
Here:
const arr = [
[{name: 'a', date:'x'}, {name: 'b', date:'y'}],
[{name: 'c', date:'x'}, {name: 'd', date:'y'}]
];
const names = arr.map(el => el.map(obj => obj.name));
console.log(names.join());
console.log(names.flat());
you can use flat() to keep names in an array or join() to merge the names into a string.
const test1= array1.map(x=> x.values)
This is returning undefined.
let requiredArr = [];
let array1 = [Array(2), Array(3), Array(2)]
let test2 = array1.map(x => x.map(y => requiredArr(y.name));
test2 will give the desired result.
Adding to Koushik's example, with ES2019, you can use flat() to flatten nested arrays:
const array = [[{name: 'test1'}, {name: 'test2'}], [{name: 'test3'}, {name: 'test4'}]]
var res = array.flat().map( ({name}) => name );
console.log(res);
Or if you have deeper levels:
const array = [[[{name: 'test1'}], {name: 'test2'}], [{name: 'test3'}, {name: 'test4'}]]
var res = array.flat(2).map( ({name}) => name );
console.log(res);
And so on.

How search two arrays and find if there is a match?

I have an array :
[{name:'blah',id:1},{name:'blah2',id:3}]
I have another array :
[{type:'blah',uid:3435},{type:'blah2',uid:3}]
I want to end up with :
[{newname:'blah2',uidid:3}]
You can see I want to match the two based on a mapping of id=uid. Really struggling to find a way to do this in js. I have underscore installed.
You could build a hash table with the first array and use it in the iteration of the second array.
var array1 = [{ name: 'blah', id: 1 }, { name: 'blah2', id: 3 }],
array2 = [{ type: 'blah', uid: 3435 }, { type: 'blah2', uid: 3 }],
hash = Object.create(null),
match = [];
array1.forEach(function (a) {
hash[a.id] = a;
});
array2.forEach(function (a) {
hash[a.uid] && match.push({ newname: a.type, uidid: a.uid });
});
console.log(match);
Since you are wanting an array with an object that uses different key names, something like this will work. It is also simple to read and to understand without any complex syntax or logic.
var arr1 = [{name: 'blah', id: 1}, {name: 'blah2', id: 3}];
var arr2 = [{type: 'blah', uid: 3435}, {type: 'blah2', uid: 3}];
var arr3 = [];
arr1.forEach(function(obj1, i) {
arr2.forEach(function(obj2) {
if (obj1.id == obj2.uid) {
arr3.push({newname: obj1.name, uidid: obj1.id})
}
})
});
console.log(arr3);

Categories

Resources