I have the following object:
"data": [
{
"label": "dataName",
"sections": [
{
"label": "label sections 1",
"fields": [
{
"id": 1,
"name": "field 1",
"value": "value field 1"
},
{
"id": 2,
"name": "field 2",
"value": "value field 2"
}
]
},
{
"label": "label sections 2",
"fields": [
{
"id": 5,
"name": "field 3",
"value": "value field 3"
}
]
}
]
I would like to create a new array by retrieving data from each field.
like this :
array [
{id: field.id, name: field.name, value: field.value }
{id: field.id, name: field.name, value: field.value }
]
I thought I would use each function like this :
_.each(data, function (elt) {
_.each(elt.ections, function (elt) {
....
})
});
but using the each function I should multiply the functions each.
Is there a solution to get the same result without using several functions each?
If you have a solution ?
Cordially
Use the reduce method:
var reduceSections = data.reduce((a,b) => (a.concat(b.sections)),[]);
var reduceFields = reduceSections.reduce((a,b) => (a.concat(b.fields)),[]);
var result = reduceFields;
console.log(result);
For more information, see
MDN JavaScript Reference - Array.prototype.reduce
MDN JavaScript Reference - Array.prototype.concat
The DEMO
var data = [{
"label": "dataName",
"sections": [{
"label": "label sections 1",
"fields": [{
"id": 1,
"name": "field 1",
"value": "value field 1"
},{
"id": 2,
"name": "field 2",
"value": "value field 2"
}]
},{
"label": "label sections 2",
"fields": [{
"id": 5,
"name": "field 3",
"value": "value field 3"
}]
}]
}];
var reduceSections = data.reduce((a,b) => (a.concat(b.sections)),[]);
var reduceFields = reduceSections.reduce((a,b) => (a.concat(b.fields)),[]);
var result = reduceFields;
console.log(result);
Only downside is that mutating the original data object will mutate the result in the array. (no shallow cloning)
That may or may not be a downside depending on the application.
If you want to clone the objects:
var clone = result.map(obj => Object.assign({},obj));
For more information, see
MDN JavaScript Reference - Object.assign
MDN JavaScript Reference - Array.prototype.map
As you are making use of lodash already, you have access to _.flatMap, _.map and _.clone.
Unfortunately, with your data structure, iterating over the arrays in your data is required, but with depending on what you are trying to achieve, there are alternatives to _.each.
Assuming you want to join all of cloned entries in fields, that are nested in each entry of the array sections, that are nested in each entry of the array data, you can use the following code:
function cloneFields(elt) { return _.map(elt.fields, _.clone) }
var allClonedFields = _.flatMap(data, elt => {
return _.flatMap(elt.sections, cloneFields);
});
The function cloneFields() is initialized outside of the loop for performance so that it isn't created on every iteration.
This code will pull out each entry in data, then from that entry pull out each entry in the sections key, then return the clone of each entry in the fields key and then join them into one large array giving the following result:
[ { id: 1, name: 'field 1', value: 'value field 1' },
{ id: 2, name: 'field 2', value: 'value field 2' },
{ id: 5, name: 'field 3', value: 'value field 3' } ]
If you don't know exactly how "deep" is your object i recommand you using recursive function. Here is what i suggest :
function recursivlyCreateObject(data) {
let result;
if(Array.isArray(data)) {
result = [];
data.forEach(function(element) {
result.push(recursivlyCreateObject(element));
});
} else {
result = {};
Object.keys(data).forEach(function(key) {
result[key] = data[key];
});
}
return result;
}
You can test it here
EDIT : note that this won't do much more than a simple console.log over the data but can help you about iterating an object recursivly
If i understand correctly, you're trying to get the fields property from each element in the array. To do this, take a look at array.map().
using array.map, you could do something like this:
let array = data.map(x => x.fields);
or:
let array = data.map(x => (
{id: x.fields.id,name: x.fields.name, value: x.fields.value }
));
https://www.w3schools.com/jsref/jsref_map.asp
Related
I am building a Blog app and I am trying to get results but it is showing duplicate results, I am trying to remove the duplicate results from the array.
But the problem is there are two key and values in each dict inside array, One is unique and other can be same so I am trying to distinct based on same array, It worked But the other key and value pair (which is unique) is not attaching with the other pair.
response which is returning from db
[
{
"id": 2,
"name": "user_1"
},
{
"id": 3,
"name": "user_3"
},
{
"id": 4,
"name": "user_3"
}
]
App.js
function App() {
const [blogs, setBlogs] = useState([]);
axios.get("retract_blogs/").then((res) => {
// Here I also want to attach "id"
setBlogs({[...new Set(res.data.data.map(x => x.name))]})
}
return(
<div>
{
blogs.map((user) =>
<div>
{user.name}
// Here I wamt to show ID
// {user.id}
</div>
}
</div>
)
}
I want to add id with x.username, I also tried using
setBlogs({data:[...new Set(res.data.data.map(x => x.name, x.id))]})
But it showed
x is not defined
But I am trying to add both name and id, and remove duplicates based on name not id.
I have tried many times but it is still not working.
To keep the id of the last occurence you can create a Map of the array keyed by name and then convert back to an array using the iterator returned by Map.values(). This works by overwriting earlier entries in the Map with the same name.
const users = [{ "id": 2, "name": "user_1" }, { "id": 3, "name": "user_3" }, { "id": 4, "name": "user_3" }];
const result = [...new Map(users.map((user) => [user.name, user])).values()];
console.log(result);
// [ { id: 2, name: 'user_1' }, { id: 4, name: 'user_3' } ]
If you instead want to keep the id of the first occurence of a name you can use a slightly modified 'group by' grouping into an object by name (here in a reduce() call, but it could easily be done in a standard loop as well) before taking the Object.values. This works by only setting the accumulator[name] property if it doesn't already exist, here using logical nullish assignment (??=)
const users = [{ "id": 2, "name": "user_1" }, { "id": 3, "name": "user_3" }, { "id": 4, "name": "user_3" }];
const result = Object.values(users.reduce((a, c) => (a[c.name] ??= c, a), {}));
console.log(result);
// [ { id: 2, name: 'user_1' }, { id: 3, name: 'user_3' } ]
I am having this array of object
let detail : [
0: {
Code: "Code 1"
Price: "0.00"
},
1: {
Code: "Code 2"
Price: "9.00"
}
]
I want to store the price in an array(for eg: result) so that I can merge it with another existing array of the object(for eg: alldetail)
result = [
0: {
Price:"0.00"
},
1: {
Price:"9.00"
},
]
Using map() method which creates a new array filled with the results of the provided function executing on every element in the calling array.
So, in your case, you'll return an object with the key Price and the value will be the current object with the value of it's Price property.
let detail = [
{
Code: "Code 1",
Price: "0.00"
},
{
Code: "Code 2",
Price: "9.00"
}
];
let result = detail.map(current => {return {Price: current.Price}});
console.log(result);
Use map to create a new array of objects.
const detail = [
{ Code: "Code 1", Price: "0.00" },
{ Code: "Code 2", Price: "9.00" }
];
const result = detail.map(({ Price }) => ({ Price }));
console.log(result);
Additional documentation
Destructuring assignment.
I am hitting an endpoint that is returning an array of objects, each object can potentially have a set of fields, e.g.,
const FIELDS = [
'id',
'title',
'contributor',
'mediatype',
'source'
]
However, some objects will only have some of those fields, some may have all.
const items = [
{
"id": 1,
"title": "some title 1",
"contributor": "bob",
"mediatype": "text"
},
{
"id": 2,
"title": "some title 2",
"mediatype": "text"
}.
{
"id": 3,
"title": "some title 3",
"mediatype": "movies"
"source": "comcast"
}
]
I want to "normalize" all the objects such that every single one contains every expected field, filling the "gaps" with null, or some falsey value such that graphql (which I intend to eventually feed it into) is happy.
const items = [
{
"id": 1,
"title": "some title 1",
"contributor": "bob",
"mediatype": "text",
"source": null
},
{
"id": 2,
"title": "some title 2",
"mediatype": "text",
"contributor": null,
"source": null
}.
{
"id": 3,
"title": "some title 3",
"mediatype": "movies",
"contributor": null,
"source": "comcast"
}
]
My "nasty" looking code looks something like this
const normalize = items =>
items.map(item => {
FIELDS.forEach(f => {
if (!item[f]) {
item[f] = null;
}
});
return item;
});
Any suggestions for writing this more elegantly - either with vanilla JS or lodash, which I am equally open to using as its already available in my codebase?
You can use spread syntax, but then it would be better to define FIELDS as a template object:
const FIELDS = {
id: null,
title: null,
contributor: null,
mediatype: null,
source: null
};
const normalize = items => items.map(item => ({...FIELDS, ...item}));
Your if (!item[f]) test will match on any falsy value, which is probably not what you want.
Instead, you should properly check if the key exists, e.g.:
if (!(f in item))
Not sure if this is any better really... but here is some equivalent alternative syntax.
Use an "equals itself or null" to squeeze out a bit more sugar:
const normalize = items =>
items.map(item => {
FIELDS.forEach(f => item[f] = item[f] || null);
return item;
});
Or test everyone's patience with this one liner:
const normalize = items =>
items.map(item => FIELDS.reduce((acc, field) => {acc[field] = item[field] || null; return acc}, item));
The choice is yours.
I have an array of objects like this:
[
{ name: "Group 1", value: "Foo" },
{ name: "Group 2", value: "Bar" },
{ name: "Group 1", value: "Baz" }
]
I'd like to use Partial Lenses library to transform these groups to keys of an object with corresponding group's items, like this:
{
"Group 1": [
{ name: "Group 1", value: "Foo" },
{ name: "Group 1", value: "Baz" }
],
"Group 2": [
{ name: "Group 2", value: "Bar" }
]
}
My current approach is like this, assuming I have the source data in a variable called data:
const grouped = L.collect([L.groupBy('name'), L.entries], data)
const setKey = [L.elems, 0]
const getName = [L.elems, 1, 0, 'name']
const correctPairs = L.disperse(setKey, L.collectTotal(getName, grouped), grouped)
L.get(L.inverse(L.keyed), correctPairs)
I don't like that I need to use the grouped and correctPairs variables to hold data, as I probably should be able to do the transformation directly in the composition. Could you help me to compose the same functionality in a more meaningful way?
Here's a Partial Lenses Playground with the above code.
I assume the goal is to actually create an isomorphism through which one can
view such an array as an object of arrays and also perform updates. Like a
bidirectional version of e.g. Ramda's
R.groupBy function.
Indeed, one approach would be to just use Ramda's
R.groupBy to implement a new primitive
isomorphism using L.iso.
Something like this:
const objectBy = keyL => L.iso(
R.cond([[R.is(Array), R.groupBy(L.get(keyL))]]),
R.cond([[R.is(Object), L.collect([L.values, L.elems])]])
)
The conditionals are needed to allow for the possibility that the data is not of
the expected type and to map the result to undefined in case it isn't.
Here is a playground with the above Ramda based
objectBy
implementation.
Using only the current version of Partial Lenses, one way to compose a similar
objectBy combinator would be as follows:
const objectBy = keyL => [
L.groupBy(keyL),
L.array(L.unzipWith1(L.iso(x => [L.get(keyL, x), x], L.get(1)))),
L.inverse(L.keyed)
]
Perhaps the interesting part in the above is the middle part that converts an
array of arrays into an array of key-array pairs (or the other way around).
L.unzipWith1
checks that all the keys within a group match, and if they don't, that group
will be mapped to undefined and filtered out by
L.array. If desired,
it is possible to get stricter behaviour by using
L.arrays.
Here is a playground with the above composed
objectBy
implementation.
You don't need any library, use a generic function that returns a reducer, that way you can use to group any collection with any key. In the example below I used this to group by name, but also by value.
const groupBy = key => (result,current) => {
let item = Object.assign({},current);
// optional
// delete item[key];
if (typeof result[current[key]] == 'undefined'){
result[current[key]] = [item];
}else{
result[current[key]].push(item);
}
return result;
};
const data = [{ name: "Group 1", value: "Foo" },{ name: "Group 2", value: "Bar" },{ name: "Group 1", value: "Baz" }];
const grouped = data.reduce(groupBy('name'),{});
console.log(grouped);
const groupedByValue = data.reduce(groupBy('value'),{});
console.log(groupedByValue);
You can use Array.reduce
let arr = [{ name: "Group 1", value: "Foo" },{ name: "Group 2", value: "Bar" },{ name: "Group 1", value: "Baz" }];
let obj = arr.reduce((a,c) => Object.assign(a, {[c.name]: (a[c.name] || []).concat(c)}), {});
console.log(obj);
I am trying to use Lodash to filter an array of objects based on a match of id's, this is what I have tried:
var team = _.find(this.teams, { 'id': this.newSchedule.team});
_.filter(this.yards, function(yard) {
return _.find(team.yards, { id: yard.id });
});
yards data:
[ { "id": 1, "name": "Test" },{ "id": 2, "name": "Test 2" } ]
team data:
[ { "id": 1, "name": "Team 1", "yards": [{ "id": 1, "name" }] ]
I want this.yards to show the yards based on the yard id from a selected team.
Its hard to understand what you mean, does the yard id match the team id?
If so it sounds like what you need to do is first find the team with the same id then grab that teams yards. Therefore I would use the map function twice:
const result = this
.yards
.map(y => team.find(t => t.id === y.id)) // join with the right team
.map(t => t.yards) // reduce to that teams yards
As team is an array, you need to iterate it before doing the _.find on an individual element in that array. It doesn't help that you called your variable team (singular). teams would make more sense.
Here is how you would change your lodash code:
var yards = [ { id: 1, name: "Test" },{ id: 2, name: "Test 2" } ],
teams = [ { id: 1, name: "Team 1", yards: [{ id: 1, name: "Missing string" }] } ]
result = _.filter(this.yards, function(yard) {
return _.some(this.teams, function(team) {
return _.find(team.yards, { id: yard.id });
});
});
console.log(result);
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.16.4/lodash.min.js"></script>
So this returns the yards that are related to at least one team.