Adding Dynamic elements/rows to multi dimensional Json array in Angularjs - javascript

I have a JSon object array that looks as below:
var myObject= [
{"name":'Tom', "city":'Chicago',"GroupCode":'1'},
{"name":'Harry', "city":'Wisconsin',"GroupCode":'1'},
{"name":'Rob', "city":'Los Angeles',"GroupCode":'2'},
{"name":'Peter', "city":'Seattle',"GroupCode":'2'},
{"name":'Dave', "city":'New York',"GroupCode":'3'},
{"name":'Steve', "city":'Boston',"GroupCode":'3}
];
I wanted to a add a new row with some sample values when ever the GroupCode is changing. My result shall look like :
var myObject= [
{"name":'Tom', "city":'Chicago',"GroupCode":'1'},
{"name":'Harry', "city":'Wisconsin',"GroupCode":'1'},
{"name":'--', "city":'--',"GroupCode":'--'},
{"name":'Rob', "city":'Los Angeles',"GroupCode":'2'},
{"name":'Peter', "city":'Seattle',"GroupCode":'2'},
{"name":'--', "city":'--',"GroupCode":'--'},
{"name":'Dave', "city":'New York',"GroupCode":'3'},
{"name":'Steve', "city":'Boston',"GroupCode":'3}
];
How can i do that ? Please help !

You can do it like this:
var myObject = [{
"name": 'Tom',
"city": 'Chicago',
"GroupCode": '1'
}, {
"name": 'Harry',
"city": 'Wisconsin',
"GroupCode": '1'
}, {
"name": 'Rob',
"city": 'Los Angeles',
"GroupCode": '2'
}, {
"name": 'Peter',
"city": 'Seattle',
"GroupCode": '2'
}, {
"name": 'Dave',
"city": 'New York',
"GroupCode": '3'
}, {
"name": 'Steve',
"city": 'Boston',
"GroupCode": '3'
}];
//store the first groupcode
var gc = myObject[0].GroupCode;
myObject.forEach(function(ob, index) {
if (gc != ob.GroupCode) {
gc = ob.GroupCode;
//insert this object
myObject.splice(index, 0, {
"name": '--',
"city": '--',
"GroupCode": '--'
});
}
})
console.log(myObject)
working code here

Related

Fuse.js - search through nested values

I use fuse.js with useExtendedSearch enabled. I have an array of objects. Each of the objects has a key of type array that contains objects.
I want to search for values in both the outer array and the inner array. It works if the search keyword is in the outer array. But it does not work, if the inner array contains the search keyword.
In the code below, I want to filter the countries such that it contains only the object whose name is exactly as the search keyword.
const data = [{
"continent": "Asia",
countries: [{
name: "Korea"
},
{
name: "Japan"
},
{
name: "China"
},
{
name: "Pakistan"
},
]
},
{
"continent": "Europe",
countries: [{
name: "Albania"
},
{
name: "France"
},
{
name: "England"
},
{
name: "Spain"
},
]
},
{
"continent": "Africa",
countries: [{
name: "Algeria"
},
{
name: "Angola"
},
{
name: "Benin"
},
{
name: "South Africa"
},
]
}
]
const options = {
useExtendedSearch: true,
keys: [
"continent",
"countries.name"
]
};
const fuse = new Fuse(data, options);
// Change the pattern
const pattern = "=Pakistan"
console.log(fuse.search(pattern))
<script src="https://cdn.jsdelivr.net/npm/fuse.js#6.6.2"></script>
But it only filters the outer array.
[{
"continent": "Asia",
countries: [{
name: "Korea"
},
{
name: "Japan"
},
{
name: "China"
},
{
name: "Pakistan"
},
]
}]
I expect it to retun:
[{
"continent": "Asia",
countries: [{
name: "Pakistan"
}]
}]
Is it possible to achive this in Fuse.js?

Optimal way to find union of two data sets

I am working on a side project where I am comparing two different databases and want to find the common elements of the data sets based on the "id" field. I want to know if there is an optimal solution instead of using two nested for loops. Is there a way to do it with a hash map? Many Thanks!
Below is the sample code I am working with.
UPDATE all ids are unique with no possibility of there being a duplicate
// data set 1
const set1 = [
{
id: "001",
name: "bob",
age: "50",
location: "texas"
},
{
id: "002",
name: "bill",
age: "51",
location: "texas"
},
{
id: "003",
name: "ben",
age: "52",
location: "texas"
},
{
id: "004",
name: "cam",
age: "53",
location: "texas"
},
{
id: "005",
name: "max",
age: "54",
location: "texas"
}
]
// data set 2
const set2 = [
{
id: "001",
name: "bob"
},
{
id: "002",
name: "bill"
}
]
// I want to create a function where I find the the common elements of the two lists based on id and put the common element of data set 1 into a list and return that list
const findUnion(set1, set2) {
// logic here, I know I can do a nested for loop but is there a more efficient way such as
// using a hashmap? ( Map() object? )
}
// desired output
const output = [
{
id: "001",
name: "bob",
age: "50",
location: "texas"
},
{
id: "002",
name: "bill",
age: "51",
location: "texas"
}
]
You can use Sets for efficient lookup:
const ids1 = new Set(set1.map(({id}) => id));
const ids2 = new Set(set2.map(({id}) => id));
const output = set1.filter(({id}) => ids1.has(id) && ids2.has(id));
console.log(output);
First of all, you're looking for the intersection, not the union.
As others have said, we can use a Set to track uniqueness. This gives us near O(1) lookup time, and allows us algorithm that runs in something like O(m + n) time where m and n are the sizes of your sets:
const intersection = (s1, s2, ids = new Set (s2 .map (x => x .id))) =>
s1 .filter (({id}) => ids .has (id))
const set1 = [{id: "001", name: "bob", age: "50", location: "texas"}, {id: "002", name: "bill", age: "51", location: "texas"}, {id: "003", name: "ben", age: "52", location: "texas"}, {id: "004", name: "cam", age: "53", location: "texas"}, {id: "005", name: "max", age: "54", location: "texas"}]
const set2 = [{id: "001", name: "bob"}, {id: "002", name: "bill"}]
console .log (intersection (set1, set2))
.as-console-wrapper {max-height: 100% !important; top: 0}
First we combine into one long array. Then group by id using reduce method. Each group contains the item and count of appearances. Finally, for each of the groups, return only those with count of appearances > 1.
Edit: fixed algorithm see code.
Edit 2: Made it more generic so order of items won't matter. This is by extending the duplicates rather then replacing them.
function findUnion(set1, set2) {
// first remove duplicates from each set
// bonus: collect duplicates
var duplicates;
function dedup(set) {
duplicates = []
return Object.values(set.reduce(function(agg, item) {
var merged = item;
if (agg[item.id]) {
merged = { ...agg[item.id],
...item
}
duplicates.push(merged)
}
agg[item.id] = merged;
return agg
}, {}));
}
set1 = dedup(set1);
set2 = dedup(set2);
// then combine
var combined = [...set1, ...set2]
// then remove duplicates again, this time keep them
dedup(combined)
return duplicates;
}
// data set 1
const set1 = [{
id: "001",
name: "bob",
age: "50",
location: "texas"
},
{
id: "002",
name: "bill",
age: "51",
location: "texas"
},
{
id: "003",
name: "ben",
age: "52",
location: "texas"
},
{
id: "004",
name: "cam",
age: "53",
location: "texas"
},
{
id: "005",
name: "max",
age: "54",
location: "texas"
},
{
id: "005",
name: "max",
age: "54",
location: "texas"
},
{
id: "005",
name: "max",
age: "54",
location: "texas"
}
]
// data set 2
const set2 = [{
id: "001",
name: "bob"
},
{
id: "002",
name: "bill"
}
]
// desired output
const output = [{
id: "001",
name: "bob",
age: "50",
location: "texas"
},
{
id: "002",
name: "bill",
age: "51",
location: "texas"
}
]
console.log(findUnion(set1, set2))

Nested filter returning empty array

Below is the data that I am receiving and I am trying to filter so that a new array contains only objects with the desired location.
However, I'm running into an issue where my function is returning [], an empty array.
data:
[
{ data: [[Object], [Object], [Object]], id: 1 },
{ data: [[Object]], id: 2 },
{ data: [[Object], [Object], [Object], [Object]], id: 3 }
];
data[1]:
{"data": [{"name": "Joe", "job": "N/A", "location": "Los Angeles"}], "id": 2}
This is my current function:
const locations = ["Los Angeles", "Chicago"];
...
const filteredData = data.filter((i) =>
i.data.filter((j) => locations.includes(j.location)),
);
return filteredData;
What is wrong and how can I fix this and get it filtering correctly?
In the callback you pass to the Array.filter(), you need to return a boolean value to filter the array. If you do not return anything, the filter returns an empty array.
But in your case, you are returning inner filtered array that returns at least an empty array and the outer filter behaves it as a true value. So the outer filter will return all of the items in the original array. (not an empty one as you stated)
Also you are returning filteredData in a place where it results in a syntax error.
const data = [
{"data": [{"name": "Joe", "job": "N/A", "location": "Los Angeles"}], "id": 2},
{"data": [{"name": "Jane", "job": "N/A", "location": "Charlotte"}], "id": 3},
]
const locations = ["Los Angeles", "Chicago"];
const filteredData = data.filter((i) =>
i.data.filter((j) => locations.includes(j.location)).length > 0,
);
console.log(filteredData);
Another Option is use some() to get your expected result. This way you don't need to loop through all item in data array comparing to filter()
const data = [
{ data: [{ name: "Joe", job: "N/A", location: "Los Angeles" }], id: 2 },
{ data: [{ name: "Jane", job: "N/A", location: "Charlotte" }], id: 3 },
{ data: [{ name: "Sam", job: "N/A", location: "SSS" }], id: 4 },
{
data: [
{ name: "John", job: "N/A", location: "AAA" },
{ name: "Doe", job: "N/A", location: "BBB" },
],
id: 5,
},
];
const locations = ["Los Angeles", "Chicago", "AAA"];
const existData = data.filter(el =>
el.data.some(item => locations.includes(item.location))
);
console.log(existData);
If you also want to filter the data array, you can do like below.
const data = [
{ data: [{ name: "Joe", job: "N/A", location: "Los Angeles" }], id: 2 },
{ data: [{ name: "Jane", job: "N/A", location: "Charlotte" }], id: 3 },
{ data: [{ name: "Sam", job: "N/A", location: "SSS" }], id: 4 },
{
data: [
{ name: "John", job: "N/A", location: "AAA" },
{ name: "Doe", job: "N/A", location: "BBB" },
],
id: 5,
},
];
const locations = ["Los Angeles", "Chicago", "AAA"];
const filteredData = data.reduce((acc, cur) => {
const filteredItem = cur.data.filter(item => locations.includes(item.location));
if (filteredItem.length) {
acc.push({ ...cur, data: filteredItem });
}
return acc;
}, []);
console.log(filteredData);

How to compare and change array of object value with object key in javascript

I would like to know how to compare and change the array value by object value in javascript
I have a arrobj and obj in which if arrobj value city and obj key saame
the change the city vaue in arrobj,
var arrobj =[
{
"id":1, "name": "xyz", "city":"IN",
"id":2, "name": "abc", "city":"CA",
"id":3, "name": "jon", "city":"MY",
"id":4, "name": "om", "city":"CH",
"id":5, "name": "ken", "city":"JP",
}
]
var obj={
"CA": "Canada",
"MY": "Myanmmar",
"IN": "India"
}
Expected Output
[
{
id:1, name: "xyz", city:"India",
id:2, name: "abc", city:"Canada",
id:3, name: "jon", city:"Myanmmar",
}
]
var arr1 = [];
var result = arrobj.map(e=>{
return Object.keys(obj).map(i=>{
if(e.city===i){
arr1.push({
...e,
city:i
})
}
})
})
console.log(arr1)
Using Array#map, you can iterate over arrobj and update city if it has a value in obj:
const
arrobj = [
{ id:1, name: "xyz", city:"IN" },
{ id:2, name: "abc", city:"CA" },
{ id:3, name: "jon", city:"MY" },
{ id:4, name: "om", city:"CH" },
{ id:5, name: "ken", city:"JP" }
],
obj = { "CA": "Canada", "MY": "Myanmmar", "IN": "India" };
const res = arrobj.map(({ city, ...e }) => ({ ...e, city: obj[city] || city }));
console.log(res);
This might be the solution you are looking for
https://jsfiddle.net/sd7102v9/1/
var arrobj =[
{id:1, name: "xyz", city:"IN"},
{id:2, name: "abc", city:"CA"},
{id:3, name: "jon", city:"MY"},
{id:4, name: "om", city:"CH"},
{id:5, name: "ken", city:"JP"},
]
var obj=
{
"CA" : "Canada",
"MY" : "Myanmmar",
"IN" : "India"
}
var result = arrobj.map(e=>
{
let city = e.city;
if(typeof obj[city] !== 'undefined')
e.city = obj[city];
return e;
})
console.log(arrobj)
The following makes sure the original array remains unchanged and only those results are returned where the city name could be resolved:
const arrobj =[
{id:1, name: "xyz", city:"IN"},
{id:2, name: "abc", city:"CA"},
{id:3, name: "jon", city:"MY"},
{id:4, name: "om", city:"CH"},
{id:5, name: "ken", city:"JP"}],
obj={"CA": "Canada","MY": "Myanmmar","IN": "India"};
res=arrobj.reduce((a,c)=>(obj[c.city] && a.push({...c,city:obj[c.city]}),a), []);
console.log(res)

Check for duplicated objects in an array populated dynamically

I'm trying to build a data structure where all elements would be grouped based on an object key.
Everything works fine except that I can't check if the new array has the data duplicated, as it's outside the for..of loop. I'm looking for a way to prevent pushing a further object if the new array already has it.
Current output (note that the list of characters from Japan appear twice)
[
[
{ "country": "US" },
[
{ "name": "Guile", "country": "US" }
]
],
[
{ "country": "Japan" },
[
{ "name": "E. Honda", "country": "Japan" },
{ "name": "Ryu", "country": "Japan" }
]
],
[
{ "country": "Japan" },
[
{ "name": "E. Honda", "country": "Japan" },
{ "name": "Ryu", "country": "Japan" }
]
],
[
{ "country": "Thailand" },
[
{ "name": "Sagat", "country": "Thailand" }
]
]
]
Expected output
[
[
{ "country": "US" },
[
{ "name": "Guile", "country": "US" }
]
],
[
{ "country": "Japan" },
[
{ "name": "E. Honda", "country": "Japan" },
{ "name": "Ryu", "country": "Japan" }
]
],
[
{ "country": "Thailand" },
[
{ "name": "Sagat", "country": "Thailand" }
]
]
]
What I have so far
var data = [
{name: 'Guile', country: 'US'},
{name: 'E. Honda', country: 'Japan'},
{name: 'Ryu', country: 'Japan'},
{name: 'Sagat', country: 'Thailand'}
]
const getNationList = (streetFighterList) => {
let filteredList = []
for (const [index, characterData] of streetFighterList.entries()) {
// .......................................................
// looking for ways here to check if `filteredList` already
// has the data I'm trying to push. Since it's empty
// I don't know how to check its index. :(
// NOTE: indexOf() doesn't seem to work
// .......................................................
const indexOf = filteredList.indexOf(streetFighterList[index].country)
if (indexOf == -1) {
filteredList.push([
{ country: characterData.country },
streetFighterList.filter((character) => {
return character.country === characterData.country
})
])
}
}
return filteredList
}
console.log(getNationList(data))
Note: I understand that given the country object is always unique this data structure would be better and easier if I used a string instead. However this is a sample data and in a real life code I do need it stored as an object.
I would recommend using some to validate as following
var data = [
{name: 'Guile', country: 'US'},
{name: 'E. Honda', country: 'Japan'},
{name: 'Ryu', country: 'Japan'},
{name: 'Sagat', country: 'Thailand'}
]
const getNationList = (streetFighterList) => {
let filteredList = []
for (const [index, characterData] of streetFighterList.entries()) {
const entry = filteredList.some(item => item[0].country === streetFighterList[index].country)
if (!entry) {
filteredList.push([
{ country: characterData.country },
streetFighterList.filter((character) => {
return character.country === characterData.country
})
])
}
}
return filteredList
}
console.log(getNationList(data))
Reduce the array to object, with the country names as the keys. Combine players that are under the same country to an object, with the player's name as the key.
When done, convert back to an array using Object.values(), and map the array to convert the player's objects to arrays via Object.values() as well.
const data = [[{"country":"US"},[{"name":"Guile","country":"US"}]],[{"country":"Japan"},[{"name":"E. Honda","country":"Japan"},{"name":"Ryu","country":"Japan"}]],[{"country":"Japan"},[{"name":"E. Honda","country":"Japan"},{"name":"Ryu","country":"Japan"}]],[{"country":"Thailand"},[{"name":"Sagat","country":"Thailand"}]]]
const result = Object.values(data.reduce((r, [c, p]) => {
if(!r[c.country]) r[c.country] = [c, {}]
const players = r[c.country][1];
p.forEach(o => { if(!players[o.name]) players[o.name] = o; })
return r;
}, {})).map(([c, p]) => [c, Object.values(p)]);
console.log(result)
You could first create a Set of unique countries and then loop through them to combine each one with a list of fighters from that country. For example:
const data = [{ name: 'Guile', country: 'US' }, { name: 'E. Honda', country: 'Japan' }, { name: 'Ryu', country: 'Japan' }, { name: 'Sagat', country: 'Thailand' }];
const countries = new Set(data.map((obj) => obj.country));
const output = [...countries].map((country) => {
const entries = data.filter((obj) => obj.country === country);
return [{ country }, entries];
});
console.log(output);
/*
[
[
{"country": "US"},
[{"name": "Guile", "country": "US"}]
],
[
{"country": "Japan"},
[{"name": "E. Honda", "country": "Japan"}, {"name": "Ryu", "country": "Japan" }]
],
[
{"country": "Thailand"},
[{"name": "Sagat", "country": "Thailand"}]
]
]
*/

Categories