JavaScript object inside Multiple array merge - javascript

I have one object inside the object list of array values, I want to merge the object value
Thanks for Help
const List = {
school1: [{studentname:'1'},{studentname:'2'}]
school2: [{studentname:'21'},{studentname:'22'}]
school3: [{studentname:'31'},{studentname:'32'}]
}
Trying Get like this
const List = [{studentname:'1'},{studentname:'2'},{studentname:'21'},{studentname:'22'},{studentname:'31'},{studentname:'32'}]

You can use Object.values() and Array.flat() to get the desired result:
const List = {
school1: [{studentname:'1'},{studentname:'2'}],
school2: [{studentname:'21'},{studentname:'22'}],
school3: [{studentname:'31'},{studentname:'32'}]
}
const result = Object.values(List).flat();
console.log('Result:', result)
.as-console-wrapper { max-height: 100% !important; }

var a = {
a1: [{name:'s1'}, {name: 's2'}],
a2: [{name:'s3'}, {name: 's4'}],
a3: [{name:'s5'}, {name: 's6'}],
}
var list = [];
Object.keys(a).forEach(x => {list = [...list, ...a[x]]})
console.log(list)

Brute force solution:
const List = {
school1: [{studentname:'1'},{studentname:'2'}],
school2: [{studentname:'21'},{studentname:'22'}],
school3: [{studentname:'31'},{studentname:'32'}]
}
let List2 = [];
for(let i of Object.values(List)){
List2.push(i)
}
console.log(List2)

Related

Search by multiple keys and values, Javascript

I'm trying to make a search function. The number of filters will change dynamically, a number of keys can be different, and the number of values, too.
My code looks like:
var data = [{"id":"123","color":"Red","model":"Tesla"},{"id":"124","color":"Black","model":"Honda"},{"id":"125","color":"Red","model":"Audi"},{"id":"126","color":"Blue","model":"Resla"}]
var keys = ["color", 'model'];
var values = ["Re"];
var result = data.filter(function(e) {
return keys.every(function(a) {
return values.includes(e[a])
})
})
console.log(result);
Is it possible to search with - startsWith() and not includes()? I guess everything should be in toLowerCase() as well?
Also can I have two separate results as two arrays if results found in one key then it should individual array? So results will be like:
[{ colors: [{"id":"123","color":"Red","model":"Tesla"},{"id":"125","color":"Red","model":"Audi"}], models: [{"id":"126","color":"Blue","model":"Resla" }] }]
Thank you very much in advance.
You need to check keys.some and not keys.every. This will check if the value is part of at least one of the keys and not all of them.
For values, you could create a dynamic regex with alternation and test value against the regex. So, values = ["Re", "Ho"] will create /Re|Ho/
const data = [{"id":"123","color":"Red","model":"Tesla"},{"id":"124","color":"Black","model":"Honda"},{"id":"125","color":"Red","model":"Audi"},{"id":"126","color":"Blue","model":"Resla"}],
keys = ["color", 'model'],
values = ["Ho"],
regex = new RegExp(values.join('|')),
output = data.filter(e => keys.some(k => regex.test(e[k])) )
console.log(output);
If you want to individual results for each key, you can loop through the keys and check for the regex individually.
const data = [{"id":"123","color":"Red","model":"Tesla"},{"id":"124","color":"Black","model":"Honda"},{"id":"125","color":"Red","model":"Audi"},{"id":"126","color":"Blue","model":"Resla"}],
keys = ["color", 'model'],
values = ["Ho", "Re"],
regex = new RegExp(values.join('|')),
group = {}
for (const o of data) {
for (const k of keys) {
if (regex.test(o[k])) {
group[k] ||= []
group[k].push(o)
}
}
}
console.log(group);
You can iterate through each key and value and look it up in object array using array#reduce
const data = [{"id":"123","color":"Red","model":"Tesla"},{"id":"124","color":"Black","model":"Honda"},{"id":"125","color":"Red","model":"Audi"},{"id":"126","color":"Blue","model":"Resla"}],
keys = ["color", 'model'],
values = ["Re"],
initial = Object.assign(...keys.map(k => ({[`${k}s`]: [] }))),
result = data.reduce((r, o) => {
keys.forEach(k => {
values.forEach(val => {
if(o[k] && o[k].startsWith(val)) {
r[`${k}s`].push(o);
}
});
});
return r;
},initial);
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }

Combine 2 JSON objects of unequal size with ID

Problem
I would like to have the below two JSON combined together using the ID and have the expected result as mentioned below. I have tried a few solutions that were available but none worked for my use case. Any suggestions will be great !!
Tried to do:
How to merge two json object values by id with plain Javascript (ES6)
Code
var json1 = [
{
"id":"A123",
"cost":"5020.67",
"fruitName":"grapes"
},
{
"id":"A456",
"cost":"341.30",
"fruitName":"apple"
},
{
"id":"A789",
"cost":"3423.04",
"fruitName":"banana"
}
];
var json2 = [
{
"id":"A123",
"quantity":"7"
},
{
"id":"A789",
"quantity":"10"
},
{
"id":"ABCD",
"quantity":"22"
}
];
Below is the code I tried:
var finalResult = [...[json1, json2].reduce((m, a) => (a.forEach(o => m.has(o.id) && Object.assign(m.get(o.id), o) || m.set(o.id, o)), m), new Map).values()];
Expected result:
[
{
"id":"A123",
"cost":"5020.67",
"fruitName":"grapes",
"quantity":"7"
},
{
"id":"A456",
"cost":"341.30",
"fruitName":"apple"
},
{
"id":"A789",
"cost":"3423.04",
"fruitName":"banana",
"quantity":"10"
},
{
"id":"ABCD",
"quantity":"22"
}
]
You can accomplish this fairly easily without getting too fancy. Here's the algorithm:
Put the items from json1 into an object by id, so that you can look them up quickly.
For each item in json2: If it already exists, merge it with the existing item. Else, add it to objectsById.
Convert objectsById back to an array. I've used Object.values, but you can also do this easily with a loop.
var json1 = [
{
"id":"A123",
"cost":"5020.67",
"fruitName":"grapes"
}, {
"id":"A456",
"cost":"341.30",
"fruitName":"apple"
}, {
"id":"A789",
"cost":"3423.04",
"fruitName":"banana"
}
];
var json2 = [
{
"id":"A123",
"quantity":"7"
}, {
"id":"A789",
"quantity":"10"
}
];
const objectsById = {};
// Store json1 objects by id.
for (const obj1 of json1) {
objectsById[obj1.id] = obj1;
}
for (const obj2 of json2) {
const id = obj2.id;
if (objectsById[id]) {
// Object already exists, need to merge.
// Using lodash's merge because it works for deep properties, unlike object.assign.
objectsById[id] = _.merge(objectsById[id], obj2)
} else {
// Object doesn't exist in merged, add it.
objectsById[id] = obj2;
}
}
// All objects have been merged or added. Convert our map to an array.
const mergedArray = Object.values(objectsById);
I think a few steps are being skipped in your reduce function. And it was a little difficult to read because so many steps are being combined in one.
One critical piece that your function does not account for is that when you add 2 numerical strings together, it concats the strings.
const stringTotal = "5020.67" + "3423.04" // result will be "5020.673423.04"
The following functions should give you the result you are looking for.
// calculating the total cost
// default values handles cases where there is no obj in array 2 with the same id as the obj compared in array1
const calcualteStringTotal = (value1 = 0, value2 = 0) => {
const total = parseFloat(value1) + parseFloat(value2)
return `${total}`
}
const calculateTotalById = (array1, array2) => {
const result = []
// looping through initial array
array1.forEach(outterJSON => {
// placeholder json obj - helpful in case we have multiple json in array2 with the same id
let combinedJSON = outterJSON;
// looping through second array
array2.forEach(innerJSON => {
// checking ids
if(innerJSON.id === combinedJSON.id) {
// calls our helper function to calculate cost
const updatedCost = calcualteStringTotal(innerJSON.cost, outterJSON.cost)
// updating other properties
combinedJSON = {
...outterJSON,
...innerJSON,
cost: updatedCost
}
}
})
result.push(combinedJSON)
})
return result
}
const combinedResult = calculateTotalById(json1, json2)
I figured that by using reduce I could make it work.
var finalResult = [...[json1, json2].reduce((m, a) => (a.forEach(o => m.has(o.id) && Object.assign(m.get(o.id), o) || m.set(o.id, o)), m), new Map).values()];

creating object from object in Javascript

I have an object.
var x = {"id":"asc","metaid":"desc"}
I want to create another object which looks something like this.
[{id: {order:"asc"}},{metaid: {order:"desc"}}]
What I have already tried is this
const sc1 = [];
var def1 = {}
for (let key of Object.keys(obj)){
def1[key] = {order: obj[key]}
}
sc1.push(def1);
The above code doesn't give required output.
Need help with this.
Thanks
Map the entries of the object to return an object with a computed property name:
var x = {"id":"asc","metaid":"desc"};
const result = Object.entries(x)
.map(([prop, order]) => ({ [prop]: { order } }));
console.log(result);
You can use Array#from
var x = {"id":"asc","metaid":"desc"};
let out = Array.from(Object.entries(x), ([prop, value]) => ({[prop]: {order: value}}));
console.log(out)

Javascript - One-liner to extract values from object to array

I quite simple one:
I have a Javascript object with some properties whose values are arrays, with the following structure:
let obj = {emails: ["xxx#yyy.com", "qqq#www.com"], nickname: ["asdf"],...}
I need to get an array of arrays with only the values, like the following:
let obj2 = [["xxx#yyy.com"], ["qqq#www.com"], ["asdf"],...]
With Object.values(obj), I get [["xxx#yyy.com", "qqq#www.com"], ["asdf"],...], which is not exactly what I am looking for, but it is a good starting point...
Also, I am looking for a one-liner to do it, if possible. Any ideas?
Thanks.
An alternative using the function reduce.
This approach adds objects and arrays from the first level.
As you can see, this approach evaluates the type of the object.
let obj = {emails: ["xxx#yyy.com", "qqq#www.com"], nickname: ["asdf"]}
var result = Object.values(obj).reduce((a, c) => {
if (Array.isArray(c)) return a.concat(Array.from(c, (r) => [r]));
return a.concat([c]);
}, []);
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
One line approach (excluding the checking for array type):
let obj = {emails: ["xxx#yyy.com", "qqq#www.com"], nickname: ["asdf"]},
result = Object.values(obj).reduce((a, c) => (a.concat(Array.from(c, (r) => [r]))), []);
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
You can use Object.values to get array of values and then concat and spread syntax ... to get flat array and then map method.
let obj = {emails: ["xxx#yyy.com", "qqq#www.com"], nickname: ["asdf"]}
const values = [].concat(...Object.values(obj)).map(e => [e])
console.log(values)

Sort two array value and merge as per date using Angular.js/JavaScript

I have two json array and both the array has date field value. Here I need to compare both the array and merge into one array. My code is below:
var firstArr=[{'name':'Ram','date':'2017-12-06'},{'name':'Raja','date':'2017-12-07'},{'name':'Rahul','date':'2017-12-08'}];
var secondArr=[{'model':'mmm','date':'2017-12-06'},{'model':'rrr','date':'2017-12-09'}];
Here I have two array and I need to compare both the array as per date and merge the both value into one single array. The expected output is given below.
var finalArr=[{'name':'Ram','date':'2017-12-06','model':'mmm'},{'name':'Raja','date':'2017-12-07','model':''},{'name':'Rahul','date':'2017-12-08','model':''},{'name':'','date':'2017-12-09','model':'rrr'}]
My expected output is given above. I was trying like below.
angular.forEach(firstArr,function(obj1){
angular.forEach(secondArr.task,function(obj2){
if (new Date(obj1.date)=== new Date(obj2.date)) {
}
})
})
But like this I am little bit confused about the two array length because it may/may not same.
I'm focusing on JS part and not on angular version.
Logic
Since you need to merge object based on a date string, you can create a hashMap with dateString as property and object as value.
Then you can use Onject.assign to merge objects. If you cannot, you can even use for..in loop or just have 2 loops and set specific property manually.
Now loop over this hashMap and retrieve grouped objects.
Sample:
var firstArr=[{'name':'Ram','date':'2017-12-06'},{'name':'Raja','date':'2017-12-07'},{'name':'Rahul','date':'2017-12-08'}];
var secondArr=[{'model':'mmm','date':'2017-12-06'},{'model':'rrr','date':'2017-12-09'}];
var hashMap = {};
[firstArr, secondArr].forEach(function(arr) {
arr.forEach(function(obj) {
hashMap[obj.date] = Object.assign(Object.create(null), hashMap[obj.date] || {}, obj);
})
});
var result = Object.keys(hashMap).map(x=> hashMap[x]);
console.log(result)
You can use array#reduce to get the merged object with the same date. Inside the array#reduce, merge objects with the same date and then get all the values using Object.values().
var firstArr=[{'name':'Ram','date':'2017-12-06'},{'name':'Raja','date':'2017-12-07'},{'name':'Rahul','date':'2017-12-08'}],
secondArr=[{'model':'mmm','date':'2017-12-06'},{'model':'rrr','date':'2017-12-09'}];
var result = firstArr.concat(secondArr).reduce((r, o) => {
r[o.date] = Object.assign({}, r[o.date] || {name:'', model: ''}, o);
return r;
},{});
var output = Object.values(result);
console.log(output);
.as-console-wrapper { max-height: 100% !important; top: 0; }
try this
var finelArr = []
angular.forEach(firstArr, function(val) {
angular.forEach(secondArr, function(item) {
if (val.date === item.date) {
finelArr.push({ name: val.name, date: val.date, model: item.model })
}
})
})
Try this. If you do not want to modify the original arrays, you will have to deep clone them beforehand. In contrast to Edison's solution, this will also include items from the second array.
var firstArr=[{'name':'Ram','date':'2017-12-06'},{'name':'Raja','date':'2017-12-07'},{'name':'Rahul','date':'2017-12-08'}];
var secondArr=[{'model':'mmm','date':'2017-12-06'},{'model':'rrr','date':'2017-12-09'}];
const newArr = (arr1, arr2) => {
const finalArr = arr1.map((firstElement) => {
firstElement.model = "";
arr2.forEach((secondElement, index) => {
if (secondElement.date === firstElement.date) {
firstElement.model = secondElement.model;
arr2.splice(index, 1);
}
});
return firstElement;
});
arr2.forEach((element) => {
element.name = "";
finalArr.push(element);
});
return finalArr;
};
console.log(newArr(firstArr, secondArr));
Angular is huge framework with big library , but only thing it need before start using correct syntax in view.
This sample worked without coding in controller:
var app = angular.module("app", []);
app.controller("ctrlA", function($scope) {
var firstArr = [{
'name': 'Ram',
'date': '2017-12-06'
}, {
'name': 'Raja',
'date': '2017-12-07'
}, {
'name': 'Rahul',
'date': '2017-12-08'
}];
var secondArr = [{
'model': 'mmm',
'date': '2017-12-06'
}, {
'model': 'rrr',
'date': '2017-12-09'
}];
$scope.ul = firstArr.concat(secondArr);
})
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="app" ng-controller="ctrlA">
<ul>
<li ng-repeat="li in ul | orderBy:'date'">
{{li.name ? li.name : li.model}} - {{li.date}}
</li>
</ul>
</div>

Categories