Javascript: merge to array of objects (SQL style join) - javascript

I have two arrays of objects:
array1 = [{id : 1, pop: 4000}, etc.]
array2 = [{id : 1, size: 2000}, etc.]
I would like to merge the two arrays (on id) for:
merged = [{id :1, pop: 4000, size: 2000}, etc.]
I saw extend and other options like concat but nothing quite what I was going for

No need for underscore, you can use Object.assign:
Working Example
var array1 = [{id : 1, pop: 4000}, {id : 2, pop: 4000}];
var array2 = [{id : 1, size: 2000}, {id : 1, blah: 4000}, {id : 2, size: 4000}];
var merged = [];
for (var i = 0; i < array1.length; i++) {
var obj = {};
for (var j = 0; j < array2.length; j++) {
if (array1[i].id === array2[j].id) {
obj = Object.assign(obj, array1[i], array2[j]);
merged.push(obj);
}
}
}

With lodash:
result = _(array1)
.concat(array2)
.groupBy('id')
.map(_.spread(_.extend))
.value();
Unlike map+find solutions, this is linear. Note that it's a "full outer" join, so the result will include non-matching elements from both arrays.

Using underscore JS :
var array1 = [{ id: 1, pop: 4000 }, { id: 2, pop: 7000 }];
var array2 = [{ id: 1, pop: 5000 }, { id: 2, pop: 6000 }];
var merge = _.map(array1, function(curr){
return _.extend(curr, _.findWhere(array2, { id: curr.id })); });
I think it should work..

A solution in plain Javascript with Array#forEach and Object.keys and an object for the reference to the array elements.
var array1 = [{ id: 1, pop: 4000 }, { id: 2, pop: 2000 }],
array2 = [{ id: 1, size: 2000 }, { id: 2, size: 0 }],
merged = [];
function getMerged(array1, array2) {
function iter(a) {
if (!obj[a.id]) {
obj[a.id] = { id: a.id };
result.push(obj[a.id]);
}
Object.keys(a).forEach(function (k) {
if (k !== 'id') {
obj[a.id][k] = a[k];
}
});
}
var result = [],
obj = Object.create(null);
array1.forEach(iter);
array2.forEach(iter);
return result;
}
console.log(getMerged(array1, array2));

You can use _.map, _.extend and _.findWhere in Underscore.
Example:
const array1 = [{
"id": 1,
"pop": 400
}, {
"id": 2,
"pop": 2000
}];
const array2 = [{
"id": 1,
"size": 5000
}, {
"id": 2,
"size": 500
}];
const mergeById = (a, b) => a.map(x => _.extend(x, _.findWhere(b, {"id": x.id})));
console.log(mergeById(array1, array2));
/* RESULT:
[
{
"id": 1,
"pop": 400,
"size": 5000
},
{
"id": 2,
"pop": 2000,
"size": 500
}
]
*/
<script src="https://cdnjs.cloudflare.com/ajax/libs/underscore.js/1.8.3/underscore-min.js"></script>

Related

Dynamic conditions of array for javascript

const conditionalArray = [
{ name: "line", condition: ">=", value: 5 },
{ name: "revene", condition: "in", value: 6 },
];
const dataTofilter = [
{ line: 3, revene: 4, sale: 3, fridge: "lg" },
{ line: 6, revene: 3, sale: 2, fridge: "samsung" },
];
I have these 2 arrays one is having conditions ( many more can be there) and second is to filter
Final result should be [{ line: 6, revene: 3, sale: 2, fridge: "samsung" }]
Something along the lines of:
const conditionalArray = [
{ name: "line", condition: ">=", value: 5 },
{ name: "revene", condition: "<", value: 6 },
];
const dataTofilter = [
{ line: 3, revene: 4, sale: 3, fridge: "lg" },
{ line: 6, revene: 3, sale: 2, fridge: "samsung" },
];
const conditions = {
'<': (x, y) => x < y,
'<=': (x, y) => x <= y,
'>': (x, y) => x > y,
'>=': (x, y) => x >= y,
};
const result = dataTofilter.filter(data => {
for (const el of conditionalArray) {
if (!conditions[el.condition](data[el.name], el.value)) {
return false;
}
}
return true;
});
console.log(result);
const newData = dataTofilter.filter((item) => {
const passedConditions = [];
conditionalArray.forEach((cond) => {
switch(cond.condition){
case ">":
passedCondition.push(item[cond.name] > cond.value);
break;
case ..... //other conditional checks
}
}); //end forEach
return Arrays.asList(passedCondition).contains(false) === false;
});
If you don't want to use eval you can do something like this. We loop through all the data first and use filter to only return values that pass our conditional check.
We then loop trough the conditional array testing each condition on the single item and save the value to passedConditions. You will need to add the rest of the conditions.
Finally we return wether the passedCondtions array did not contain a false value. This would mean we passed all the conditional checks.
I'm really not a big fan of it. But I don't see another way as eval() to make the condition work as an actual operator without doing plenty of manual checks. Also the following solution assumes that every item in dataToFilter has a corresponding item in conditionalArray.
const conditionalArray = [
{ name: "line", condition: ">=", value: 5 },
{ name: "revene", condition: "<", value: 6 },
];
const dataTofilter = [
{ line: 3, revene: 4, sale: 3, fridge: "lg" },
{ line: 6, revene: 3, sale: 2, fridge: "samsung" },
];
const result = dataTofilter.filter((item, i) =>
eval(
`${item[conditionalArray[i].name]}${conditionalArray[i].condition}${
conditionalArray[i].value
}`
)
);
console.log(result);

Calculate Percentage in Java Script and Output Result

I am trying to use below Script to Get the Average of Disconnect Devices .The results are output in group for each Test Customer .
var dataObject = [{
"Customer_Nbr": "13",
"Customer_Name": "Test1",
"Connected_Devices": 7,
"Disconnected_Devices": 1,
"Total_Devices": 8
},
{
"Customer_Nbr": "13",
"Customer_Name": "Test1",
"Connected_Devices": 6,
"Disconnected_Devices": 2,
"Total_Devices": 8
},
{
"Customer_Nbr": "12",
"Customer_Name": "Test3",
"Connected_Devices": 8,
"Disconnected_Devices": 2,
"Total_Devices": 10
}
];
groups = dataObject.reduce(function(r, o) {
var k = o.Customer_Nbr + o.Customer_Name;
if (r[k]) {
if (o.Disconnected_Devices)
(r[k].Disconnected_Devices += o.Disconnected_Devices) && ++r[k].Average;
} else {
r[k] = o;
r[k].Average = 1; // taking 'Average' attribute as an items counter(on the first phase)
}
return r;
}, {});
// getting "average of Points"
var result = Object.keys(groups).map(function(k) {
groups[k].Average = Math.round(groups[k].Disconnected_Devices / groups[k].Average);
return groups[k];
});
console.log(result)
Now I also want grouped output to have a percentage calculation which would be result/Total_Devices * 100 .
Output Should be Something like Assuming Total_Devices Count is constant in Input data -
[
{
Customer_Nbr: '13',
Customer_Name: 'Test1',
Connected_Devices: 7,
Disconnected_Devices: 3,
Total_Devices: 8,
Average: 2
Percent: 25
},
{
Customer_Nbr: '12',
Customer_Name: 'Test3',
Connected_Devices: 8,
Disconnected_Devices: 2,
Total_Devices: 10,
Average: 2
Percent: 20
}
]
Something like this maybe?
var dataObject = [
{
Customer_Nbr: "13",
Customer_Name: "Test1",
Connected_Devices: 7,
Disconnected_Devices: 1,
Total_Devices: 8,
},
{
Customer_Nbr: "13",
Customer_Name: "Test1",
Connected_Devices: 6,
Disconnected_Devices: 2,
Total_Devices: 8,
},
{
Customer_Nbr: "12",
Customer_Name: "Test3",
Connected_Devices: 8,
Disconnected_Devices: 2,
Total_Devices: 10,
},
];
groups = dataObject.reduce(function (r, o) {
var k = o.Customer_Nbr + o.Customer_Name;
if (r[k]) {
if (o.Disconnected_Devices)
(r[k].Disconnected_Devices += o.Disconnected_Devices) && ++r[k].Average;
} else {
r[k] = o;
r[k].Average = 1; // taking 'Average' attribute as an items counter(on the first phase)
}
return r;
}, {});
// getting "average of Points"
var result = Object.keys(groups).map(function (k) {
groups[k].Average = Math.round(
groups[k].Disconnected_Devices / groups[k].Average
);
groups[k].percentage = (groups[k].Average/groups[k].Total_Devices) * 100;
return groups[k];
});
console.log(result);

Adding Ids to an Array

I tried adding an id property to the objects in my sorted output, but all I'm doing is not working. Is there anything I should have done?
My Code Below:
var arr = [{ one: 2 },
{ two: 3 },
{ three: 4 },
{ four: 1 }];
const arr1 = arr.reduce((a,b) => ({...a,...b}), {})
var sorting = Object.entries(arr1).sort((a, b) => b[1] - a[1]);
console.log(sorting);
Expected Result:
var arr1 = [{ name: "three", value: 4, id: 1 },
{ name: "two", value: 3, id: 2 },
{ name: "one", value: 2, id: 3 },
{ name: "four", value: 1, id: 4 }];
Object.assign can do what you did with reduce, and I would not call that result arr1, as it is not an array, but a plain object.
In the final step it helps to use destructuring and map to an object literal with shortcut notation:
const arr = [{one: 2}, {two: 3}, {three: 4}, {four: 1}];
const obj = Object.assign({}, ...arr);
const sorted = Object.entries(obj).sort((a, b) => b[1] - a[1]);
const result = sorted.map(([text, value], i) => ({ text, value, id: i+1}));
console.log(result);
/*If i console.log(sorting) I have
[['three', 4 ], ['two', 3 ], ['one', 2 ], ['four', 1 ],]
Without Ids but i want something like the expected result below*/
/* Expected Result
[['three', 4 id = 1], ['two', 3 id = 2], ['one', 2 id = 3], ['four', 1 id = 4],]
*/
UPD, sorry, didn't get it right first time
var empty = [];
var arr = [{
one: 2
}, {
two: 3
}, {
three: 4
},{
four: 1
}];
const arr1 = arr.reduce((a,b) => ({...a,...b}), {})
const sorting = Object.entries(arr1).sort((a, b) => b[1] - a[1]);
// Add indexes starting from 1
const indexed = sorting.map((a,b) => a.push({ "id": b+1 }));
console.log(sorting);
I am going to go with a guess here that you want a descending sorted array of objects, adding an id property based on the original index + 1 of each original object. We can do that by reference to the object key (first property 0) when we sort after we add the ids to the original objects in a new array.
// not used in the question/issue
//var empty = [];
var arr = [{
one: 2
}, {
two: 3
}, {
three: 4
}, {
four: 1
}];
const newArr = [];
arr.forEach(function(currentValue, index, arr) {
currentValue.id = index + 1;
newArr.push(currentValue);
}, arr);
//console.log("arrObj:", newArr);
var sorted = newArr.sort(function(a, b) {
return b[Object.keys(b)[0]] - a[Object.keys(a)[0]];
});
console.log("sorted:", sorted);
EDIT: new based on comment
var arr = [{
one: 2
}, {
two: 3
}, {
three: 4
}, {
four: 1
}];
const newArr = [];
arr.forEach(function(currentValue, index, arr) {
let newValue = {};
newValue.text = Object.keys(currentValue)[0];
newValue.Value = currentValue[Object.keys(currentValue)[0]];
newValue.id = index + 1;
newArr.push(newValue);
}, arr);
//console.log("arrObj:", newArr);
var sorted = newArr.sort(function(a, b) {
return b.Value - a.Value;
});
console.log("sorted:", sorted);
output of this last is
sorted: [
{
"text": "three",
"Value": 4,
"id": 3
},
{
"text": "two",
"Value": 3,
"id": 2
},
{
"text": "one",
"Value": 2,
"id": 1
},
{
"text": "four",
"Value": 1,
"id": 4
}
]

Merge arrays into one

I'm trying merge arrays into one in javascript.
I have this Array:
[{ID: 111, SEG: 4}, {ID: 111, SEG:
3}]
And I need this:
[{ID: 111, SEG: [3, 4]}]
This can be approximated to a solution, depending on the data:
var items = [
{
id: 1,
value: 5
},
{
id: 1,
value: 3
},
{
id: 2,
value: 40
},
{
id: 2,
value: 35
}
];
var group = function (arr, groupBy) {
var values = {};
arr.forEach(function (element) {
var item = element;
var index = item[groupBy];
if (!values[index]) {
values[index] = item;
}
else {
item.value += values[index].value;
}
values[index] = item;
});
return Object.keys(values).map(function (k) { return values[k]; });
};
console.log(group(items, 'id'));
The Problem can be solved using reduce.
let dataJ = [{ID: 111, SEG: 4}, {ID: 111, SEG: 3}]
let newData = dataJ.reduce(function(acc, curr) {
let index = acc.findIndex(item => item.ID === curr.ID);
if (index === -1) {
acc.push(curr);
} else {
if (!acc[index].SEG || !Array.isArray(acc[index].SEG)) {
acc[index].SEG = [];
}
acc[index].SEG.push(curr.SEG);
}
return acc;
}, []);
console.log(newData); // [{ID: 111, SEG: [3, 4]}]

Flatten an array of objects into a single array

I have an array of an object with dynamic keys
response = [{"1": 1}, {"2": 1}, {"3": 1}, {"4": 0}, {"5": 0}];
I want to flatten this array of an object into a single array
Output = [1, 1, 1, 0, 0]
I tried the following:
const test2 = this.response.map(obj => {
Object.keys(obj).map(function(key){
return obj[key]
})
});
const test = this.response.reduce(function(prev, curr){
console.log(curr)
return (curr) ? prev.concat(curr): prev;
},[]);
You can just use map and object.values
response = [{"1": 1}, {"2": 1}, {"3": 1}, {"4": 0}, {"5": 0}]
const vals = response.map(o => Object.values(o)[0])
console.log(vals)
You can use .map() with .concat():
let data = [{"1": 1}, {"2": 1}, {"3": 1}, {"4": 0}, {"5": 0}];
let result = [].concat(...data.map(Object.values));
console.log(result);
Use reduce and for..in to loop over the object
let response = [{
"1": 1
},
{
"2": 1
},
{
"3": 1
},
{
"4": 0
},
{
"5": 0
}
]
let k = response.reduce(function(acc, curr) {
for (let keys in curr) {
acc.push(curr[keys])
}
return acc;
}, [])
console.log(k)
response = [{"1": 1},{"2": 1},{"3": 1},{"4": 0},{"5": 0}]
var newArray = []
for (element of response) {
Object.keys(element).map(key => {
newArray.push(element[key])
})
}
console.log(newArray)

Categories

Resources