I have this array of objects.
var priceArray = [
{ "foo": 1, "bar": 2, "price": 3 },
{ "foo": 2, "bar": 123, "price": 124 },
{ "foo": 2, "bar": 2, "price": 5 },
{ "foo": 112, "bar": 2, "price": 75 },
{ "foo": 2, "bar": 3, "price": 5 },
{ "foo": 3, "bar": 2, "price": 3 },
{ "foo": 3, "bar": 4, "price": 7 },
{ "foo": 4, "bar": 3, "price": 4 },
{ "foo": 4, "bar": 4, "price": 6 }
];
I have another array of objects.
var dataArray = [
{ foo: 0.25, bar: 1 },
{ foo: 0.5, bar: 1 },
{ foo: 1, bar: 1 },
{ foo: 1, bar: 2 },
{ foo: 2, bar: 1 },
{ foo: 2, bar: 2 },
{ foo: 2, bar: 4 },
{ foo: 3, bar: 2 },
{ foo: 4, bar: 1 },
{ foo: 4, bar: 2 },
{ foo: 4, bar: 4 },
];
I want to add price in dataArray which price row foo and bar values are closest greater in priceArray.
for example - filtered data should like this
var filterDataArray = [
{ foo: 0.25, bar: 1, price: 3 },
{ foo: 0.5, bar: 1, price: 3 },
{ foo: 1, bar: 1, price: 3 },
{ foo: 1, bar: 2, price: 3 },
{ foo: 2, bar: 1, price: 5 },
{ foo: 2, bar: 2, price: 5 },
{ foo: 2, bar: 4, price: 7 },
{ foo: 3, bar: 2, price: 3 },
{ foo: 4, bar: 1, price: 4 },
{ foo: 4, bar: 2, price: 4 },
{ foo: 4, bar: 4, price: 6 },
];
If I sort priceArray with foo and bar value with help of these codes and then filter this array with dataArray. So, I didn't get my solution. like -
priceArray = priceArray.sort(function(a, b) {
return a.foo - b.foo || a.bar - b.bar;
});
or
priceArray = _.sortBy(( _.sortBy(priceArray, 'bar')), 'foo');
or
priceArray = _.orderBy(priceArray, ['foo', 'bar'], ['asc', 'asc']);
// create new data array with price
const dataNewArray = [];
dataArray.map(dataObj => {
const dataNewObj = {};
for(const priceObject of priceArray) {
if (dataObj.foo <= priceObject.foo && dataObj.bar <= priceObject.bar) {
dataNewObj.foo = dataObj.foo;
dataNewObj.bar = dataObj.bar;
dataNewObj.price = priceObject.price;
break;
}
}
dataNewArray.push(dataNewObj);
});
but it's solution is
dataNewArray = [
{ foo: 0.25, bar: 1, price: 3 },
{ foo: 0.5, bar: 1, price: 3 },
{ foo: 1, bar: 1, price: 3 },
{ foo: 1, bar: 2, price: 3 },
{ foo: 2, bar: 1, price: 5 },
{ foo: 2, bar: 2, price: 5 },
{ foo: 2, bar: 4, price: 124 },
{ foo: 3, bar: 2, price: 3 },
{ foo: 4, bar: 1, price: 4 },
{ foo: 4, bar: 2, price: 4 },
{ foo: 4, bar: 4, price: 6 }
];
So, you can see in this object { foo: 2, bar: 4, price: 124 }, price should be 7, not 124.
How to solve my problem with help of anything js features like Lodash, or any algorithm. I tried many solutions at StackOverflow but maximum solutions for single attribute in object.
You need to sort by the geometric distance of the items and pick the first one which match.
var priceArray = [{ foo: 1, bar: 2, price: 3 }, { foo: 2, bar: 123, price: 124 }, { foo: 2, bar: 2, price: 5 }, { foo: 112, bar: 2, price: 75 }, { foo: 2, bar: 3, price: 5 }, { foo: 3, bar: 2, price: 3 }, { foo: 3, bar: 4, price: 7 }, { foo: 4, bar: 3, price: 4 }, { foo: 4, bar: 4, price: 6 }],
dataArray = [{ foo: 0.25, bar: 1 }, { foo: 0.5, bar: 1 }, { foo: 1, bar: 1 }, { foo: 1, bar: 2 }, { foo: 2, bar: 1 }, { foo: 2, bar: 2 }, { foo: 2, bar: 4 }, { foo: 3, bar: 2 }, { foo: 4, bar: 1 }, { foo: 4, bar: 2 }, { foo: 4, bar: 4 }],
result;
priceArray.sort((a, b) =>
(Math.pow(a.foo, 2) + Math.pow(a.bar, 2)) - (Math.pow(b.foo, 2) + Math.pow(b.bar, 2))
);
result = dataArray.map(({ foo, bar }) => ({
foo,
bar,
price: priceArray.find(o => o.foo >= foo && o.bar >= bar).price
}));
console.log(result); // the result
console.log(priceArray); // the sorted array
.as-console-wrapper { max-height: 100% !important; top: 0; }
Related
This question already has answers here:
How can I group an array of objects by key?
(32 answers)
Closed 1 year ago.
I am a beginner in javascript and i have a little problem.
i want to change the structure of array for rendering in React Native using section List,
I got this JSON from Web Api
[
{
title: "Test",
c: 1,
d: 2,
},
{
title: "Test",
c: 3,
d: 4,
},
{
title: "Test",
c: 5,
d: 6,
},
{
title: "Test01",
c: 1,
d: 2,
},
{
title: "Test01",
c: 3,
d: 4,
},
{
title: "Test01",
c: 5,
d: 6,
},
{
title: "Test02",
c: 1,
d: 2,
},
{
title: "Test02",
c: 3,
d: 4,
},
{
title: "Test02",
c: 5,
d: 6,
},
];
And I want to change this JSON like this
[
{
title: "Test",
data: [
{ c: 1, d: 2 },
{ c: 3, d: 4 },
{ c: 5, d: 6 },
],
},
{
title: "Test01",
data: [
{ c: 1, d: 2 },
{ c: 3, d: 4 },
{ c: 5, d: 6 },
],
},
{
title: "Test02",
data: [
{ c: 1, d: 2 },
{ c: 3, d: 4 },
{ c: 5, d: 6 },
],
},
];
It would be simpler to key your data to the test name, but you can achieve what you want by mapping your array like this:
let new_array=[];
your_array.forEach(elem => {
let title = elem.title;
let matchingIndex = newArray.findIndex(a => a.title = title);
if (matchingIndex === -1) {
new_array.push({title}
matchingIndex = new_array.length - 1;
}
let dataColumns = ['c', 'd'];
let data = {};
dataColumns.forEach(col => {
data[col] = elem[col];
});
if (!Array.isArray(new_array[matching_index].data)) {
isArray(new_array[matching_index].data = [];
}
new_array[matching_index].data.push(data);
});
You can perform reduce operation in the array and get the desired format.
const items = [
{
title: "Test",
c: 1,
d: 2,
},
{
title: "Test",
c: 3,
d: 4,
},
{
title: "Test",
c: 5,
d: 6,
},
{
title: "Test01",
c: 1,
d: 2,
},
{
title: "Test01",
c: 3,
d: 4,
},
{
title: "Test01",
c: 5,
d: 6,
},
{
title: "Test02",
c: 1,
d: 2,
},
{
title: "Test02",
c: 3,
d: 4,
},
{
title: "Test02",
c: 5,
d: 6,
},
];
const formatted = items.reduce((carry, current) => {
// generating the placeholder format to put the data
if(!carry.hasOwnProperty(current.title)) {
carry[current.title] = {
title: current.title,
data: []
};
}
// Setting the data in unique name
carry[current.title].data.push({ c: current.c, d: current.d });
return carry;
}, []);
// formatted will have key value pair
console.log(Object.values(formatted));
A reduce function to accumulate the result in an array:
const raw = [{
title: 'Test',
c: 1,
d: 2,
},
{
title: 'Test',
c: 3,
d: 4,
},
{
title: 'Test',
c: 5,
d: 6,
},
{
title: 'Test01',
c: 1,
d: 2,
},
{
title: 'Test01',
c: 3,
d: 4,
},
{
title: 'Test01',
c: 5,
d: 6,
},
{
title: 'Test02',
c: 1,
d: 2,
},
{
title: 'Test02',
c: 3,
d: 4,
},
{
title: 'Test02',
c: 5,
d: 6,
},
];
const result = raw.reduce((acc, {
title,
...data
}) => {
const index = acc.findIndex((elem) => title === elem.title);
if (index === -1) acc.push({
title,
data: [data]
});
else acc[index].data.push(data);
return acc;
}, []);
console.log(result);
const input =[
{
title: "Test",
c: 1,
d: 2,
},
{
title: "Test",
c: 3,
d: 4,
},
{
title: "Test",
c: 5,
d: 6,
},
{
title: "Test01",
c: 1,
d: 2,
},
{
title: "Test01",
c: 3,
d: 4,
},
{
title: "Test01",
c: 5,
d: 6,
},
{
title: "Test02",
c: 1,
d: 2,
},
{
title: "Test02",
c: 3,
d: 4,
},
{
title: "Test02",
c: 5,
d: 6,
},
];
let result = {};
input.forEach((e)=>{
if(!result[e.title]){
result[e.title] = {data:[]};
}
result[e.title]['data'].push({ c:e.c, d:e.d});
});
let restructured =[];
Object.keys(result).forEach((key)=>{
restructured.push({
title: key, data:result[key].data
})
});
console.log(restructured)
var data = [
{
title: "Test",
c: 1,
d: 2,
},
{
title: "Test",
c: 3,
d: 4,
},
{
title: "Test",
c: 5,
d: 6,
},
{
title: "Test01",
c: 1,
d: 2,
},
{
title: "Test01",
c: 3,
d: 4,
},
{
title: "Test01",
c: 5,
d: 6,
},
{
title: "Test02",
c: 1,
d: 2,
},
{
title: "Test02",
c: 3,
d: 4,
},
{
title: "Test02",
c: 5,
d: 6,
},
];
console.log('data',data)
function analyse(data){
var tmp = {}
for(let item of data){
if(tmp[item.title]){
tmp[item.title].data.push({c:item.c,d:item.d})
}else{
tmp[item.title] ={
data: [{c:item.c,d:item.d}]
}
}
}
console.log('tmp',tmp)
var results = []
for(let key in tmp){
results.push({title:key,data:tmp[key].data})
}
console.log('results',JSON.stringify(results))
return results
}
analyse(data)
Hi have an array of object with 4 properties, i need to extract only 2 from them.
sample array of object
const arr=[
module:{
module1:{
foo: 1,
bar: 2,
anotherfoo: 5
}, module2:{
foo: 3,
bar: 4,
anotherfoo: 8
},module3:{
foo: 7,
bar: 6,
anotherfoo: 3
},module4:{
submodule{
foo: 9,
bar: 0,
anotherfoo: 1
}
}
}];
How can I use map to extract module1 and module4.submodule into a new array.
You need to provide a specific key when destructuring an object.
Error:
const { module4.submodule } = { module4: { submodule: 4 } };
Good:
const { module4: { submodule } = { module4: { submodule: 4 } };
Same applies for creating an object, you can't return { module4.submodule }, but you could return { module4Submodule: submodule }.
Here's some potential solutions:
Input: Array, Output: Array
const arr = [
{
module: {
module1: {
foo: 1,
bar: 2,
anotherfoo: 5
},
module2: {
foo: 3,
bar: 4,
anotherfoo: 8
},
module3: {
foo: 7,
bar: 6,
anotherfoo: 3
},
module4: {
submodule: {
foo: 9,
bar: 0,
anotherfoo: 1
}
}
}
}
];
const newArr = arr.map(({ module: { module1, module4 } }) => (
{ module1, module4Submodule: module4.submodule }
));
console.log(newArr);
Input: Object, Output: Object
const obj = {
module: {
module1: {
foo: 1,
bar: 2,
anotherfoo: 5
},
module2: {
foo: 3,
bar: 4,
anotherfoo: 8
},
module3: {
foo: 7,
bar: 6,
anotherfoo: 3
},
module4: {
submodule: {
foo: 9,
bar: 0,
anotherfoo: 1
}
}
}
};
const { module: { module1, module4: { submodule } } } = obj;
const newObj = { module1, module4Submodule: submodule };
console.log(newObj);
You could implement a getDotPath for object
const getDotPath = (dotPath, obj) => {
try {
return dotPath.split(".").reduce((acc, prop) => acc[prop], obj)
} catch (err) {
return undefined
}
}
const arr = [
{
module: {
module1: {
foo: 1,
bar: 2,
anotherfoo: 5,
},
module2: {
foo: 3,
bar: 4,
anotherfoo: 8,
},
module3: {
foo: 7,
bar: 6,
anotherfoo: 3,
},
module4: {
submodule: {
foo: 9,
bar: 0,
anotherfoo: 1,
},
},
},
},
]
const dotPaths = ["module1", "module4.submodule"]
const res = arr.map((el) =>
dotPaths.map((dotPath) => getDotPath(dotPath, el.module))
)
console.log(res)
I have a normalized Object like this (for example):
const raw = {
1: { foo: 1, bar: 1, flag: 0 },
4: { foo: 4, bar: 4, flag: 1 },
11: { foo: 11, bar: 11, flag: 0 },
...
}
I wanna delete values which have flag: 1.
{
1: { foo: 1, bar: 1, flag: 0 },
11: { foo: 11, bar: 11, flag: 0 },
...
}
How can I do this immutably?
You can use Object.values() and Array.prototype.filter()
var obj = {
1: { foo: 1, bar: 1, flag: 0 },
2: { foo: 2, bar: 2, flag: 1 },
3: { foo: 3, bar: 3, flag: 0 }
}
var newobj = Object.assign({}, Object.values(obj).filter(o => o.flag != 1));
console.log(newobj);
You can use reduce() to keep the keys:
var obj = {
1: { foo: 1, bar: 1, flag: 0 },
2: { foo: 2, bar: 2, flag: 1 },
3: { foo: 3, bar: 3, flag: 0 }
}
var newobj = Object.keys(obj).reduce((a,c) => {
if(obj[c].flag != 1)
a[c] = obj[c]; return a;
},{});
console.log(newobj);
You can object filtering by lodashjs.
https://lodash.com/docs/#filter
_.filter(obj, o => !o.flag);
You can use Object.keys() and .reduce() methods:
let data = {
1: { foo: 1, bar: 1, flag: 0 },
2: { foo: 2, bar: 2, flag: 1 },
3: { foo: 3, bar: 3, flag: 0 }
};
let result = Object.keys(data).reduce((a, c) => {
if(data[c].flag !== 1)
a[c] = Object.assign({}, data[c]);
return a;
}, {});
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
I am trying to transform a nested structure, using the library of lodash, I have achieved the expected result, but they are not functional if the structure changes, so I come to you to help me make more robust the function that transforms the JSON.
the initial structure looks like this
const data = {
foo: {
bar: {
baz: [{ a: 1, b: 2, c: 3 }]
},
baz: {
bar: [{ a: 1, b: 2, c: 3 }]
},
foo: {
bar: [{ a: 1, b: 2, c: 3 }]
}
},
bar: {
baz: {
bar: [{ a: 1, b: 2, c: 3 }]
}
},
baz: {
foo: {
bar: [{ a: 1, b: 2, c: 3 }]
}
}
};
after being transformed
const transform = [
{
name: 'barfoo',
results: [{ a: 1, b: 2, c: 3 }]
},
{
name: 'bazfoo',
results: [{ a: 1, b: 2, c: 3 }]
},
{
name: 'foofoo',
results: [{ a: 1, b: 2, c: 3 }]
},
{
name: 'bazbar',
results: [{ a: 1, b: 2, c: 3 }]
},
{
name: 'foobaz',
results: [{ a: 1, b: 2, c: 3 }]
}
];
The idea of the transformation is to join the nested key of the first level with the key of the parent node to generate the value of name in the new object and the value of the object in the 2 level as the value of results
for example for the first iteration of foo object in data
name = key(foo.bar) + key(foo)
results = value(foo.bar.baz)
name = 'barfoo'
results = [{ a: 1, b: 2, c: 3 }]
name = key(foo.baz) + key(foo)
results = value(foo.baz.bar)
name = 'bazfoo'
results = [{ a: 1, b: 2, c: 3 }]
name = key(foo.foo) + key(foo)
results = value(foo.foo.bar)
name = 'foofoo'
results = [{ a: 1, b: 2, c: 3 }]
and so with the other objects that are inside data.
I'm not sure if the structure will ever vary, but I added a few extra test cases so you can see how this will behave in some additional scenarios.
const data = {
foo: {
bar: {
baz: [{ a: 1, b: 2, c: 3 }]
},
baz: {
bar: [{ a: 1, b: 2, c: 3 }]
},
foo: {
bar: [{ a: 1, b: 2, c: 3 }]
}
},
bar: {
baz: {
bar: [{ a: 1, b: 2, c: 3 }]
}
},
baz: {
foo: {
bar: [{ a: 1, b: 2, c: 3 }]
}
},
a1: {
a2: [{ a: 1, b: 2, c: 3 }]
},
b1: [{ a: 1, b: 2, c: 3 }],
c1: {
c2: {
c3: {
c4: [{ a: 1, b: 2, c: 3 }]
}
},
c5: [{ a: 1, b: 2, c: 3 }]
},
d1: {
d2: {
d3: undefined
}
},
e1: {
e2: {
e3: null
}
},
f1: {
f2: {
// Ignored
}
}
};
function transformObject(object, name) {
if (!name) {
name = "";
}
return _.flatten(_.map(object, function(value, key) {
if (typeof value === "undefined"
|| value === null
|| _.isArray(value)) {
return {
name: name,
results: value
}
}
var objectName = key + name;
return transformObject(value, objectName);
}));
}
transformObject(data);
Lets say I have and array made up of objects:
var points = [
{ id: 1, a: 0, b: 3 },
{ id: 2, a: 4, b: -1 },
{ id: 3, a: -1, b: 5 },
{ id: 4, a: 41, b: 2 },
{ id: 5, a: 69, b: 3 },
]
I want to iterate through each item and add a + b to get a new item d. I then want to add d within each object in the array to get a new value. When I try the below, it just adds 5 extra objects rather than appending the new element (key=value, ex: d: 3) to each individual object. What am I doing wrong here?
points.forEach((item) => {
var d = Math.abs(item.x) + Math.abs(item.y);
console.log(d);
points.item.push('d: ' + d);
});
Try following
var points = [{ id: 1, a: 0, b: 3 },{ id: 2, a: 4, b: -1 },{ id: 3, a: -1, b: 5 },{ id: 4, a: 41, b: 2 },{ id: 5, a: 69, b: 3 }];
points.forEach(o => o.d = Math.abs(o.a) + Math.abs(o.b));
console.log(points);
#jcbridwe, you can use assign() method on Object to add missing property from source object to target object.
Please have a look at the below code.
Try the below code online at http://rextester.com/EPHYV10615.
var points = [
{ id: 1, a: 0, b: 3 },
{ id: 2, a: 4, b: -1 },
{ id: 3, a: -1, b: 5 },
{ id: 4, a: 41, b: 2 },
{ id: 5, a: 69, b: 3 },
]
for(var index in points){
var a = points[index].a;
var b = points[index].b;
Object.assign(points[index], {d: a+b});
}
console.log(points);
ยป Output
[ { id: 1, a: 0, b: 3, d: 3 },
{ id: 2, a: 4, b: -1, d: 3 },
{ id: 3, a: -1, b: 5, d: 4 },
{ id: 4, a: 41, b: 2, d: 43 },
{ id: 5, a: 69, b: 3, d: 72 } ]
Mutable approach:
points.forEach(o => o.d = o.a + o.b);
Immutable approach:
const newPoints = points.map(o => Object.assign({}, o, {d: o.a + o.b}))