Combine two arrays into one by matching elements using Javascript - javascript

I have two arrays. One fetched from an API the other fetched from firebase. They both have a similar key inside of them, that being the tld. As seen below.
API Array
[
{
"tld" : "com",
"tld_type": 1,
},
"tld" : "org",
"tld_type" : 1,
}
]
Firebase Array
[
{
"TLD" : "com",
"register_price" : 14.99
},
{
"TLD" : "org",
"register_price" : 15.99
}
]
I want to combine these two arrays into one and return it like below
[
{
"tld" : "com",
"tld_type" : 1,
"register_price" : 14.99
},
{
"tld" : "org",
"tld_type" : 1,
"register_price" : 15.99
}
]
I've done some google searching and found concact but that doesn't seem to be using the key to find the match. How would I do this?

You can use map and create a new object whose keys and values will be from the other two arrays and return that object. map will create a new array of objects
let api = [{
"tld": "com",
"tld_type": 1,
},
{
"tld": "org",
"tld_type": 1,
}
]
let fb = [{
"TLD": "com",
"register_price": 14.99
},
{
"TLD": "org",
"register_price": 15.99
}
]
let k = api.map(function(item, index) {
let obj = {};
obj.tld = item.tld;
obj['tld_type'] = item['tld_type'];
obj['register_price'] = fb[index]['register_price']
return obj;
});
console.log(k)

There is no unique method for solving that kind of issue. You'll have to loop through all elements and add register_price property if that property exists in firebase array. In shortest possible:
let combined = apiArray.map(ele=>{
let machedElement = fbArray.find(e => e.TLD === ele.tld)
if(machedElement != undefined) ele.register_price = machedElement.register_price
return ele
})
In case if you want to merge all properties not only register_price:
let combined = apiArray.map(ele=>{
let machedElement = fbArray.find(e => e.TLD === ele.tld)
if(machedElement != undefined) {
let mergedObject = Object.assign(ele, machedElement)
return mergedObject
}else{
return ele
}
})

Related

Grouping elements of array on the basis of property

I have a array as follows:
data = [
{
"id":1
"name":"london"
},
{
"id":2
"name":"paris"
},
{
"id":3
"name":"london"
},
{
"id":4
"name":"paris"
},
{
"id":5
"name":"australia"
},
{
"id":6
"name":"newzearland"
}
]
At runtime this array can have n number of elements. I want to group this array with respect to name attribute. All the elements with same name should be moved to a separate array. I don't know the what value can name have in advance. This is coming at runtime. For example, from above array I want final output as follows:
output:
newArray1 = [
{
"id":1
"name":"london"
},
{
"id":3
"name":"london"
}
]
newArray2 = [
{
"id":2
"name":"paris"
},
{
"id":4
"name":"paris"
}
]
newArray3 = [
{
"id":5
"name":"australia"
}
]
newArray4 = [
{
"id":6
"name":"newzearland"
}
]
How can I do that?
As Teemu has already pointed out in a comment, creating new variables to store the data is not ideal. You would have no way of knowing how many groups you've created and using variables that you can't be sure exist is not the best way to write code. Fortunately, JavaScript has objects, which can store data like this in a much cleaner way. Here's the code I've come up with:
function groupBy(arr, key) {
let res = {}
for (let element of arr) {
if (res.hasOwnProperty(element[key])) {
res[element[key]].push(element)
} else {
res[element[key]] = [element]
}
}
return res
}
This code is not the best, most efficient code ever, but it is written to be easier to understand for someone still learning. This code loops over every element in your data and checks whether our result already contains an array for elements with that name. If there's already an array for elements with that name, the current element is added to it. If there isn't one, a new one is created with the current element inside it. To do exactly what you want, you'd call this function with groupBy(data, "name") and assign it to a new variable like groupedData (THIS DOES NOT MODIFY THE DATA, IT RETURNS A NEW OBJECT OF GROUPED DATA) .
Start by getting all the unique .names, then map them to the original array filtered by each .name:
const data = [{
"id": 1, "name": "london"
},
{
"id": 2, "name": "paris"
},
{
"id": 3, "name": "london"
},
{
"id": 4, "name": "paris"
},
{
"id": 5, "name": "australia"
},
{
"id": 6, "name": "newzearland"
}
];
const newData = [...new Set(data
//Get all names in an array
.map(({name}) => name))]
//For each name filter original array by name
.map(n => data.filter(({name}) => n === name));
console.log( newData );
//OUTPUT: [newArray1, newArray2, .....]
You can get the expected result with grouping by key approach.
const data = [{"id":1,"name":"london"},{"id":2,"name":"paris"},{"id":3,"name":"london"},{"id":4,"name":"paris"},{"id":5,"name":"australia"},{"id":6,"name":"newzearland"}];
const result = Object.values(data.reduce((acc, obj) =>
({ ...acc, [obj.name]: [...(acc[obj.name] ?? []), obj] }), {}));
console.log(result);
const [newArray1, newArray2, newArray3, newArray4, ...rest] = result;
console.log('newArray1:', newArray1);
console.log('newArray2:', newArray2);
console.log('newArray3:', newArray3);
console.log('newArray4:', newArray4);
.as-console-wrapper{min-height: 100%!important; top: 0}

Ask for help on how to get all the filtered list from specific array

I have an object in an array called "Person".
Within the object "Person", there is an array called "info".
My goal is to get all the values with the prefix "age:" in an array "info" when filtering by "gender:male". So, my desired output will be 1 to 9 because I want also to remove duplicates.
Below is my code but the results are only two values (1 and 4). Maybe the output is one value per person.
I spent a lot of hours playing the code but no luck. That's why I bring my problem here hoping anybody who is an expert on this can help me.
<script>
var array = [
{
"person": {
"info": [
"age:1",
"age:2",
"age:3",
"age:4",
"age:5",
"age:6",
"gender:male"
]
},
"person": {
"info": [
"age:4",
"age:5",
"age:6",
"age:7",
"age:8",
"age:9",
"gender:male"
]
},
"person": {
"info": [
"age:8",
"age:9",
"age:10",
"age:11",
"age:12",
"age:13",
"gender:female"
]
}
}
]
var filteredAges = [];
for (i = 0; i < array.length; i++) {
var infoGroup = array[i].person.info,
ageGroup = [];
for (j = 0; j < infoGroup.length; j++) {
ageGroup.push(infoGroup[j]);
var ageInfo = ageGroup.find(ages => ages.includes('age:'));
};
if (ageInfo) {
if (filteredAges.indexOf(ageInfo) == -1) {
filteredAges.push(ageInfo)
}
}
}
for (i = 0;i < filteredAges.length; i++) {
console.log(filteredAges[i]);
}
</script>
Seems like all your object keys are just person i.e
[
{
person: {...},
person: {...},
person: {...}
}
]
So when the variable array is evaluated it just has one person
You need to restructure your data maybe like below or something similar
Example - 1
[
{ person: {...} },
{ person: {...} },
{ person: {...} },
]
Example - 2
[
[ { person: {...} } ],
[ { person: {...} } ],
[ { person: {...} } ]
]
After fixing this you can try debugging your problem
If you want to get all items in info array that has "age:"
you can use filter like this
const ageInfos = [
"age:8", "age:9",
"age:10", "age:11",
"age:12", "age:13",
"gender:female"
].filter(x => x.startsWith("age:"))
Your output - ageInfos will be
["age:8", "age:9", "age:10", "age:11", "age:12", "age:13"]
You can also use Set to only collect unique strings or just push everything to an array and later use Set to return only unique values like this
const arrayWithDuplicates = ['a', 1, 'a', 2, '1'];
const unique = [...new Set(arrayWithDuplicates)];
console.log(unique); // unique is ['a', 1, 2, '1']
First of all, your JSON is wrong. You just overright person object.
Data structure is really awful, I would recommend you to rethink it.
Assuming person will not be overwritten I came up with this solution.
var array = [
{
"person": {
"info": [
"age:1",
"age:2",
"age:3",
"age:4",
"age:5",
"age:6",
"gender:male"
]
},
"person1": {
"info": [
"age:4",
"age:5",
"age:6",
"age:7",
"age:8",
"age:9",
"gender:male"
]
},
"person2": {
"info": [
"age:8",
"age:9",
"age:10",
"age:11",
"age:12",
"age:13",
"gender:female"
]
}
}
]
let agesArray = []
let ages = []
array.forEach((peopleObj) => {
for (const index in peopleObj) {
ages = peopleObj[index].info.map((age) => {
const ageNumber = age.split(':')[1]
if (parseInt(ageNumber)) {
return ageNumber
}
}).filter(val => !!val)
agesArray = [...agesArray, ...ages]
}
})
Thanks a lot guys. I'll apply all of your ideas and try if it can solve my problem.

how to update a particular json data object which belongs to browser local-storage

This is Browser localstorage Object referred as dataset
let dataset = localStorage.getItem('dataset') !== null ? leech : [];
[
{
"id": 123,
"name": "abc"
},
{
"id": 456,
"name": "bcd"
}
]
This is the initial data object available I want to add more field to a particular id.
This is what I want :
[
{
"id": 123,
"name": "abc"
},
{
"id": 456,
"name": "bcd",
"status":1
}
]
This my code to find the particular id
const user = dataset.find(user => user.id == 456);
Now how can I add status to user and update the user in the dataset?
You've already found the user by using Array.prototype.find() so all you need to do then is add the status property
// const dataset = JSON.parse(localStorage.getItem("dataset"))
const dataset = [{"id":123,"name":"abc"},{"id":456,"name":"bcd"}]
const user = dataset.find(({ id }) => id === 456)
if (user) {
user.status = 1
}
console.info(dataset)
.as-console-wrapper { max-height: 100% !important }
If you then want to store the modified data back into localStorage, use localStorage.setItem() and JSON.stringify()
localStorage.setItem("dataset", JSON.stringify(dataset))
If you want keep dataset initial value, and would like to get a new array, you can use Array.reduce() method.
const dataset = [
{
"id": 123,
"name": "abc"
},
{
"id": 456,
"name": "bcd"
}
]
const output = dataset.reduce((acc, cur) => {
if (cur.id === 456) cur.status = 1;
acc.push(cur);
return acc;
}, []);
console.log(output);
If you want to update dataset, you can use Array.forEach() method.
const dataset = [
{
"id": 123,
"name": "abc"
},
{
"id": 456,
"name": "bcd"
}
]
dataset.forEach(user => {
if (user.id === 456) user.status = 1;
});
console.log(dataset);
You could do with Array#Findindex with callback return function. so could pass the originaldata,searchId and update object. In this method you could updated object easily
Why i suggest findIndex
Because findindex not running entire loop or iteration. If the match
detect on first iteration they will break the loop and returning the
result.For long iteration its more faster than other loop (reduce,forEach)
const data = [ { "id": 123, "name": "abc" }, { "id": 456, "name": "bcd" } ]
function update(dataset,searchId,addtionObject){
let ind = dataset.findIndex(({id}) => id == searchId);
dataset[ind] = {...dataset[ind],...addtionObject}; //join the new and old array
return dataset
}
console.log(update(data,456,{status:1}))
If you want to create new state objet, you can use immer for that.
Immer will produce the nextState based on the mutations to the draft state.
import produce from "immer";
const baseState = [
{
id: 123,
name: "abc",
},
{
id: 456,
name: "bcd",
},
];
const nextState = produce(baseState, (draftState) => {
draftState[1].status = 1;
});

Form Array of objects using an array and an object

I have an object and an array of following kind
var sourceObject = { "item1" : 15 , "item2" : 20 " }
var feature = ["field1", "field2" ]
I am trying to convert the above object into an array of objects.
Number of items in the object as well as the array will be same
Resultant array of objects should like this:
var result = [ { "name" : "field1" , "value" : 15 } , { "name" : "field2" , "value": 20 }]
The ultimate goal is to read it from the sourceObject to get the each value and then pick each value from the "feature" array toform an object
Approach I have tried so far:
let result = [];
for (let value of Object.values(sourceObject)) {
let row = { "field" : "XYZ" , "value": value };
tableData.push(row);
}
Loop over the keys of sourceObject and then use Array.map()
var sourceObject = {
"item1": 15,
"item2": 20
}
var feature = ["field1", "field2"]
var result = Object.keys(sourceObject).map((key, index) => {
return {
name: feature[index],
value: sourceObject[key]
}
});
console.log(result);
Your object doesn't always guarantee order, so using .values(), .keys() etc... won't necessarily always guarantee your result. Instead, you can get the number from your fieldN string using a regular expression. Here N represents the itemN you want to retrieve from your object. Using this, you can .map() each fieldN to an object from your sourceObject.
See example below:
const sourceObject = { "item1" : 15 , "item2" : 20 };
const feature = ["field1", "field2" ];
const res = feature.map((name, i) => {
const [n] = name.match(/\d+$/g);
const value = sourceObject[`item${n}`];
return {name, value};
});
console.log(res);

Javascript: Split array of objects into seperate arrays with dynamic names depending on property value

I have an array containing objects. Now I want to slice the array to new arrays containing only those objects matching a certain property value.
Ideally the new array names should be created dynamically.
The original array looks like this:
specificSlotButtonArray = [
{slotStarttime:"06:00:00", slotTimespan:1},
{slotStarttime:"09:00:00", slotTimespan:1},
{slotStarttime:"12:00:00", slotTimespan:2},
{slotStarttime:"15:00:00", slotTimespan:2},
{slotStarttime:"18:00:00", slotTimespan:3}
];
The new arrays should look like this:
timespan1 = [
{slotStarttime:"06:00:00", slotTimespan:1},
{slotStarttime:"09:00:00", slotTimespan:1}
]
timespan2 = [
{slotStarttime:"12:00:00", slotTimespan:2},
{slotStarttime:"15:00:00", slotTimespan:2}
]
timespan3 = [
{slotStarttime:"18:00:00", slotTimespan:3}
]
If possible, I want to avoid javascript syntax / functions, which are not supported by IE and some other older browsers.
I already tried to work with reduce() and slice(), but did not find a solution.
You can simply achieve your desired outcome using reduce, as you can produce an object using reduce, here's an example of how you could do it.
As you can see, it'll check that the relevant property on the object isn't null, if it is, then it's set to an empty array, after this check, it's safe to simply push the relevant values onto the array, like so.
var array = [{
slotStarttime: "06:00:00",
slotTimespan: 1
},
{
slotStarttime: "09:00:00",
slotTimespan: 1
},
{
slotStarttime: "12:00:00",
slotTimespan: 2
},
{
slotStarttime: "15:00:00",
slotTimespan: 2
},
{
slotStarttime: "18:00:00",
slotTimespan: 3
}
];
var newObject = array.reduce(function(obj, value) {
var key = `timespan${value.slotTimespan}`;
if (obj[key] == null) obj[key] = [];
obj[key].push(value);
return obj;
}, {});
console.log(newObject);
Use a generic group by key reducer. I will take it from a previous answer of mine. It is an elegant and simple way to generate a function that group your data by a particular key that comes as an argument.
const groupBy = key => (result,current) => {
const item = Object.assign({},current);
if (typeof result[current[key]] == 'undefined'){
result[current[key]] = [item];
}else{
result[current[key]].push(item);
}
return result;
};
const specificSlotButtonArray = [
{slotStarttime:"06:00:00", slotTimespan:1},
{slotStarttime:"09:00:00", slotTimespan:1},
{slotStarttime:"12:00:00", slotTimespan:2},
{slotStarttime:"15:00:00", slotTimespan:2},
{slotStarttime:"18:00:00", slotTimespan:3}
];
const timespan = specificSlotButtonArray.reduce(groupBy('slotTimespan'),{});
console.log(timespan);
You could reduce the array by taking an object for the part arrays.
var specificSlotButtonArray = [{ slotStarttime: "06:00:00", slotTimespan: 1 }, { slotStarttime: "09:00:00", slotTimespan: 1 }, { slotStarttime: "12:00:00", slotTimespan: 2 }, { slotStarttime: "15:00:00", slotTimespan: 2 }, { slotStarttime: "18:00:00", slotTimespan: 3 }],
timespan1 = [],
timespan2 = [],
timespan3 = [];
specificSlotButtonArray.reduce(function (r, o) {
r[o.slotTimespan].push(o);
return r;
}, { 1: timespan1, 2: timespan2, 3: timespan3 });
console.log(timespan1);
console.log(timespan2);
console.log(timespan3);
.as-console-wrapper { max-height: 100% !important; top: 0; }
The following soluce iterates once on specificSlotButtonArray using Array.reduce. This soluce will adapt to any number of slotTimespan.
const specificSlotButtonArray = [{
slotStarttime: '06:00:00',
slotTimespan: 1,
},
{
slotStarttime: '09:00:00',
slotTimespan: 1,
},
{
slotStarttime: '12:00:00',
slotTimespan: 2,
},
{
slotStarttime: '15:00:00',
slotTimespan: 2,
},
{
slotStarttime: '18:00:00',
slotTimespan: 3,
},
];
// Loop through the array
const splitted = specificSlotButtonArray.reduce((tmp, x) => {
// Look if we got already an array having the slotTimespan of the current
// item to treat
const match = tmp.find(y => y.some(z => z.slotTimespan === x.slotTimespan));
// If we have such array, push the data into it
if (match) {
match.push(x);
} else {
// If we don't create a new array
tmp.push([x]);
}
return tmp;
}, []);
console.log(splitted);
If you want to deals with the array straight after the Array.reduce you can use destructuration :
const [
timespan1,
timespan2,
timespan3
] = specificSlotButtonArray.reduce((tmp, x) => {
You can use this function to create separate arrays grouped by slotTimespan,
specificSlotButtonArray = [
{slotStarttime:"06:00:00", slotTimespan:1},
{slotStarttime:"09:00:00", slotTimespan:1},
{slotStarttime:"12:00:00", slotTimespan:2},
{slotStarttime:"15:00:00", slotTimespan:2},
{slotStarttime:"18:00:00", slotTimespan:3}
];
function groupBy(arr, property) {
return arr.reduce(function(memo, x) {
if (!memo[x[property]]) { memo[x[property]] = []; }
memo[x[property]].push(x);
return memo;
}, {});
}
console.log(groupBy(specificSlotButtonArray, "slotTimespan"));

Categories