How to create every combination possible between two array of objects? - javascript

I have two arrays of objects, i.e. origin and destination. I am trying to find out all possible combinations that can be made from the two arrays to make a final array.
Example:
origin = [
{
id: 1,
regionName: "Africa North"
},
{
id: 2,
regionName: "Africa West"
}
];
destination: [
{
id: 5,
regionName: "Gulf"
},
{
id: 8,
regionName: "Middle East"
},
{
id: 9,
regionName: "Central America"
}
]
The final array should give me,
finalArray = [
{
originRegion: "Africa North",
destinationRegion: "Gulf",
ts: "1606370160"
},
{
originRegion: "Africa North",
destinationRegion: "Middle East",
ts: "1606370160"
},
{
originRegion: "Africa North",
destinationRegion: "Central America",
ts: "1606370160"
},
{
originRegion: "Africa West",
destinationRegion: "Gulf",
ts: "1606370160"
},
{
originRegion: "Africa West",
destinationRegion: "Middle East",
ts: "1606370160"
},
{
originRegion: "Africa West",
destinationRegion: "Central America",
ts: "1606370160"
},
]
I tried looking for some Permutations and combinations on two array of objects but didn't find get any suitable answer.
This is what I am trying:
useEffect(() => {
var origin = [
{
id: 1,
regionName: "Africa North"
},
{
id: 2,
regionName: "Africa West"
}
];
var destination = [
{
id: 5,
regionName: "Gulf"
},
{
id: 8,
regionName: "Middle East"
},
{
id: 9,
regionName: "Central America"
}
];
var finalArray = []
for (var i = 0; i < origin.length; i++) {
for (var j = 0; j < destination.length; j++) {
finalArray.push(origin[i].regionName + destination[j].regionName)
}
}
console.log("finalArray", finalArray)
}, []);
Thank you in advance.

Looks like you have the double looping part, but the object you are pushing into your array isn't what you say you expect. You are doing simple string concatenation.
origin[i].regionName + destination[j].regionName
Here is what I think is a more "react" way to loop over the data and return a result array. Reduce the origin array into a new array, mapping in the combined object with the destination array.
origin.reduce(
(result, origin) => [
...result,
...destination.map((destination) => ({
originreagion: origin.regionName,
destinationRegion: destination.regionName,
ts: "1606370160" // <-- set your real timestamp here
}))
],
[]
);
const origin = [
{
id: 1,
regionName: "Africa North"
},
{
id: 2,
regionName: "Africa West"
}
];
const destination = [
{
id: 5,
regionName: "Gulf"
},
{
id: 8,
regionName: "Middle East"
},
{
id: 9,
regionName: "Central America"
}
];
const result = origin.reduce(
(result, origin) => [
...result,
...destination.map((destination) => ({
originreagion: origin.regionName,
destinationRegion: destination.regionName,
ts: "1606370160"
}))
],
[]
);
console.log(result)

Related

Consolidate JSON objects from CSV

I need to consolidate an array containing JSON objects that were retrieved from a CSV file.
CSV file:
sector,subsector,codigo
sector1,subsector1,001
sector1,subsector2,002
sector2,subsector1,003
sector3,subsector1,004
sector3,subsector3,005
This is my code:
const csvtojson = function(){
let pathToCsv = './dummy-sectores.csv'
csv({
colParser:{
"sector.subsector":{
flat: true,
cellParser: "subsector"
}
}
})
.fromFile(pathToCsv)
.then((json) => {
const n = {}
json.forEach((a)=>{
n.sector = a.sector
n.subsector = a.subsector
})
console.log(n)
})
.catch((e) => console.log(e))
}
What I get:
[ { codigo: '001',
sector: 'sector 1',
subsector: 'sector 1 subsector 1' },
{ codigo: '002',
sector: 'sector 1',
subsector: 'sector 1 subsector 2' },
{ codigo: '003',
sector: 'sector 2',
subsector: 'sector 2 subsector 1' },
{ codigo: '004',
sector: 'sector 3',
subsector: 'sector 3 subsector 1' },
{ codigo: '005',
sector: 'sector 3',
subsector: 'sector 3 subsector 2' } ]
What I'm trying to get:
{
"sector1":
[{"subsector": "subsector1", "codigo": 1},
{"subsector": "subsector2", "codigo": 2}],
"sector2":
[{"subsector": "subsector1", "codigo": 3}],
"sector3":
[{"subsector": "subsector1", "codigo": 4},
{"subsector": "subsector2", "codigo": 5}]
}
Whenever I try to use map or forEach function it just messes up everything.
Quite easy - suppose you use this Keyang / node-csvtojson
My raw JSON parsed from your CSV placed to string looks like:
[{ "sector": "sector1", "subsector": "subsector1", "codigo": "001" },
{ "sector": "sector1", "subsector": "subsector2", "codigo": "002" },
{ "sector": "sector2", "subsector": "subsector1", "codigo": "003" },
{ "sector": "sector3", "subsector": "subsector1", "codigo": "004" },
{ "sector": "sector3", "subsector": "subsector3", "codigo": "005" }]
Formatting is not exactly same, but looks almost like JSON you wanted(?)
{"sector1":
[{"subsector":"subsector1","codigo":1},
{"subsector":"subsector2","codigo":2}],
"sector2":
[{"subsector":"subsector1","codigo":3}],
"sector3":
[{"subsector":"subsector1","codigo":4},
{"subsector":"subsector3","codigo":5}]}
const csvtojson = function() {
let CSV = 'sector,subsector,codigo\nsector1,subsector1,001\nsector1,subsector2,002\nsector2,subsector1,003\nsector3,subsector1,004\nsector3,subsector3,005';
csv({
colParser: {
"sector.subsector": {
flat: true,
cellParser: "subsector"
}
}
})
.fromString(CSV)
.then((json) => {
const n = {}
json.forEach((a) => {
n[a.sector] = n[a.sector] || [];
n[a.sector].push(a);
delete a.sector;
a.codigo = parseInt(a.codigo);
})
console.log(JSON.stringify(
n
).replace(/:\[/g, ':\n[').replace(/([^"]),([\{"])/g, '$1,\n$2'))
})
.catch((e) => console.log(e))
}
csvtojson();
<script src="https://cdn.rawgit.com/Keyang/node-csvtojson/d41f44aa/browser/csvtojson.min.js"></script>

Splitting a Map instance into two separate arrays

I'm trying to split an instance of Map into separate arrays. An example of the Map instance I have:
new Map([
["Guatemala", 7],
["Albania", 7],
["Finland", 3],
["Canada", 12],
["Japan", 21],
...
]);
There's more data, but just wanted to show a small sample.
I produced it from the raw data I get from an API in JSON format:
[
{
id: 1,
import_country: "Argentina",
model: "riolet",
make: "Audi",
sold_by: "Huey Bagster",
sale_price: 18643,
},
{
id: 2,
import_country: "China",
model: "MKX",
make: "Lincoln",
sold_by: "Wolf Coller",
sale_price: 16850,
},
{
id: 3,
import_country: "Portugal",
model: "Coupe Quattro",
make: "Audi",
sold_by: "Doroteya McLewd",
sale_price: 13733,
},
]
So I took the import_country and counted the number of times it appeared and created map as an instance of Map.
In order to get the keys and values of map in separate arrays, I tried the following:
map.forEach(key, value){
country.append(key);
numCountry.append(value);
}
where country and numCountry are separate arrays.
My end desired output is:
country = ["Guatemala", "Albania"...] and
numCountry = [7, 7, ...]
If your map is an instance of Map, then use its keys and values methods:
const map = new Map([
["Guatemala", 7],
["Albania", 7],
["Finland", 3],
["Canada", 12],
["Japan", 21],
]);
const countries = [...map.keys()];
const numCountries = [...map.values()];
console.log(countries);
console.log(numCountries);
Kindly take as sample, modify according to your need.
You can use Object.reduce(data) to loop over data and update count for countries.
const data = [
{
id: 1,
import_country: "Argentina",
model: "riolet",
make: "Audi",
sold_by: "Huey Bagster",
sale_price: 18643,
},
{
id: 2,
import_country: "China",
model: "MKX",
make: "Lincoln",
sold_by: "Wolf Coller",
sale_price: 16850,
},
{
id: 3,
import_country: "Portugal",
model: "Coupe Quattro",
make: "Audi",
sold_by: "Doroteya McLewd",
sale_price: 13733,
},
{
id: 4,
import_country: "Portugal",
model: "Coupe Quattro",
make: "Audi",
sold_by: "Doroteya McLewd",
sale_price: 13733,
},
];
const map = data.reduce((m, { id, import_country }) => {
if (!m[import_country]) m[import_country] = 0;
m[import_country] += 1;
return m;
}, {});
console.log(map);
const counties = Object.keys(map)
const numCounts = Object.values(map)
console.log(counties)
console.log(numCounts)
//OR:
let countries2 = [],
numCountries2 = [];
Object.entries(map).forEach(([key, value]) => {
countries2.push(key)
numCountries2.push(value)
});
console.log(countries2);
console.log(numCountries2);
Use JSON.parse to convert it to an array then just loop and push id of each item on country code array and name on ct array
var str = `[
{
"id": 1,
"import_country": "Argentina",
"model": "riolet",
"make": "Audi",
"sold_by": "Huey Bagster",
"sale_price": 18643
},
{
"id": 2,
"import_country": "China",
"model": "MKX",
"make": "Lincoln",
"sold_by": "Wolf Coller",
"sale_price": 16850
},
{
"id": 3,
"import_country": "Portugal",
"model": "Coupe Quattro",
"make": "Audi",
"sold_by": "Doroteya McLewd",
"sale_price": 13733
}
]`
var arr = JSON.parse(str);
var ct = [];
var code = [];
for (var i = 0; i < arr.length; i++) {
ct.push(arr[i].import_country);
code.push(arr[i].id)
}
console.log(ct); //countries
console.log(code); //codes

How to remove a key value pair from object while updating values of remaining objects?

const initialState = {
loading: null,
error: null,
lineItems: [
{
id: 1,
product_name: "Elbow 15",
product_disc: 1,
sub_total: 5548.95,
product_unit: "Nos",
…
}
{
id: 2,
product_name: "Tee 15",
product_disc: 3,
sub_total: 24.25,
product_unit: "Nos",
…
}
{
id: 3,
product_name: "",
product_disc: 0,
sub_total: 0
}
]
lineItems represent rows in a grid (I am using react-data-grid)
id property values are used to populate the first column ("Serial Number") of the grid
If a user deletes a row (e.g. middle object in the above case),
how to update the above object, so that is becomes
lineItems: [
{
id: 1,
product_name: "Elbow 15",
product_disc: 1,
sub_total: 5548.95,
product_unit: "Nos",
…
}
{
id: 2,
product_name: "",
product_disc: 0,
sub_total: 0
}
]
You can use delete to remove a property from an object. Then you'll need to loop through the remaining properties and update their keys and the id properties within them.
function removeLineItem(state, index) {
delete state.lineItems[index];
Object.keys(state.lineItems).forEach(k => {
if (state.lineItems[k].id > index) {
state.lineItems[k].id = k - 1; // decrement id
state.lineItems[k - 1] = state.lineItems[k]; // decrement key
delete state.lineItems[k]; // remove old key
}
});
}
const initialState = {
loading: null,
error: null,
lineItems: {
0: {
id: 1,
product_name: "Elbow 15",
product_disc: 1,
sub_total: 5548.95,
product_unit: "Nos",
},
1: {
id: 2,
product_name: "Tee 15",
product_disc: 3,
sub_total: 24.25,
product_unit: "Nos",
},
2: {
id: 3,
product_name: "",
product_disc: 0,
sub_total: 0
}
}
};
removeLineItem(initialState, 1);
console.log(initialState);
You can use delete keyword to delete specific key from your object.
delete object['key']

Convert js Array to Dictionary/Hashmap

I'm trying to convert an array of objects into a hashmap. I only have some parts of ES6 available and I cannot use Map as well.
The objects in the array are quite simple, e.g. {nation: {name: string, iso: string, scoringPoints: number}. I need to sort them by scoringPoints.
I want now a "dictionary" holding the rank by iso -> {[iso:string]:number}.
I already tried (from here (SO))
const dict = sortedData.reduce((prev, curr, index, array) => (
{ ...array, [curr.nation.iso]: ++index }
), {});
But dict turns out to be an Object with indices starting with 0. Hopefully there is just a small thing I don't see. But currently my head is spinning how to convert a simple array into a hashmap-like object.
Maybe Array.map?
I should also note that I am using TypeScript which I also had some trouble before when not typed correctly.
const test = [
{ nation: { name: "Germany", iso: "DE", rankingPoints: 293949 } },
{ nation: { name: "Hungary", iso: "HU", rankingPoints: 564161 } },
{ nation: { name: "Serbia", iso: "SR", rankingPoints: 231651 } }
];
const sorted = test.sort((a, b) => a.nation.rankingPoints - b.nation.rankingPoints);
const dict = sorted.reduce((prev, curr, index, array) => ({ ...array, [curr.nation.iso]: ++index }), {});
console.log(JSON.stringify(dict));
is showing
{
"0": {
"nation": {
"name": "Serbia",
"iso": "RS",
"rankingPoints": 231651
}
},
"1": {
"nation": {
"name": "Germany",
"iso": "DE",
"rankingPoints": 293949
}
},
"2": {
"nation": {
"name": "Hungary",
"iso": "HU",
"rankingPoints": 564161
}
},
"HU": 3
}
in the console.
As per comments, what I want is a hashmap-like object like
{
"HU": 1,
"DE": 2,
"RS": 3
}
where the property-value is the rank (+1) in the sorted data so I can simply get the rank by accessing dict["DE"] which would return 2.
Capture the position of each key in your data using forEach or reduce:
const test = [
{ nation: { name: "Germany", iso: "DE", rankingPoints: 293949 } },
{ nation: { name: "Hungary", iso: "HU", rankingPoints: 564161 } },
{ nation: { name: "Serbia", iso: "SR", rankingPoints: 231651 } }
];
const sorted = test.sort((a, b) => a.nation.rankingPoints - b.nation.rankingPoints);
// Using forEach:
var dict = {}
sorted.forEach((el, index) => dict[el.nation.iso] = sorted.length - index);
// Using reduce:
dict = sorted.reduce(
(dict, el, index) => (dict[el.nation.iso] = sorted.length - index, dict),
{}
);
console.log(dict)
console.log("dict['DE'] = ", dict['DE'])
Output:
{
"SR": 3,
"DE": 2,
"HU": 1
}
dict['DE'] = 2
(Note the order of properties is not significant in an object used as a map - if you need a specific order use an array.)
It is also possible to achieve this using Array.map and Object.fromEntries:
const test = [
{ nation: { name: "Germany", iso: "DE", rankingPoints: 293949 } },
{ nation: { name: "Hungary", iso: "HU", rankingPoints: 564161 } },
{ nation: { name: "Serbia", iso: "SR", rankingPoints: 231651 } }
];
const sorted = test.sort((a, b) => a.nation.rankingPoints < b.nation.rankingPoints ? 1 : (a.nation.rankingPoints > b.nation.rankingPoints ? -1 : 0));
const dict = Object.fromEntries(sorted.map((c, index) => [c.nation.iso, index + 1]));
console.log(dict);
const test = [
{ nation: { name: "Germany", iso: "DE", rankingPoints: 293949 } },
{ nation: { name: "Hungary", iso: "HU", rankingPoints: 564161 } },
{ nation: { name: "Serbia", iso: "SR", rankingPoints: 231651 } }
];
const sorted = test.sort((a, b) => b.nation.rankingPoints - a.nation.rankingPoints);
const dict = sorted.reduce((result, curr, index, array) => ({ ...result, [curr.nation.iso]: ++index }), {});
console.log(JSON.stringify(dict));

Normalizr with nested array of objects

I have a nested array of objects like this:
var matchs = [
{
id: 10689,
sport: 'Tennis',
players: [
{
id: 22,
name:'Rafa Nadal',
country: 'Spain',
odds: [
{id: 1, bookie_1: 1.60},
{id: 2, bookie_2: 1.61},
{id: 3, bookie_3: 1.62},
]
},
{
id: 23,
name:'Roger Federer',
country: 'Spain',
odds: [
{id: 4, bookie_1: 2.60},
{id: 5, bookie_2: 2.61},
{id: 6, bookie_3: 2.62},
]
}
]
},
{
id: 12389,
sport: 'Tennis',
players: [
{
id: 45,
name:'Fernando Verdasco',
country: 'Spain',
odds: [
{id: 7, bookie_1: 2.60},
{id: 8, bookie_2: 2.61},
{id: 9, bookie_3: 2.62},
]
},
{
id: 65,
name:'Andy Murray',
country: 'Spain',
odds: [
{id: 10, bookie_1: 1.60},
{id: 11, bookie_2: 1.61},
{id: 12, bookie_3: 1.62},
]
}
]
}
];
I want to use normalizr to simplify array and use with redux. I have read the Normalizr documentation but it has few examples and I do not know what I am doing wrong.
I have tried the following code without success. The result I get is an array with undefined.
import { normalize, schema } from 'normalizr';
const match = new schema.Entity('matchs');
const player = new schema.Entity('players');
const odd = new schema.Entity('odds');
match.define({
player: [player],
odd: [odd]
});
console.log(normalize(matchs, [match]));
I need something like this:
{
result: "123",
entities: {
"matchs": {
"123": {
id: "123",
players: [ "1","2" ],
odds: [ "1", "2" ]
}
},
"players": {
"1": { "id": "1", "name": "Rafa Nadal" },
"2": { "id": "2", "name": "Andy Murray" }
},
"odds": {
"1": { id: "1", "bookie_1": "1.20" }
"2": { id: "2", "bookie_2": "1.21" }
"3": { id: "3", "bookie_3": "1.22" }
}
}
}
I cannot find a straight solution using only normalizr, so my only choice is to pre-format the data before passing to the normalizer.
const preformattedData = data.map(sport => {
const oddArrays = sport.players.map(player => player.odds || []);
return {
...sport,
odds: [].concat.apply([], oddArrays)
}
})
const odd = new schema.Entity('odds')
const player = new schema.Entity('players',
{
odds: [ odd ]
}
)
const sport = new schema.Entity('sports',
{
players: [ player ],
odds: [odd]
}
)
const normalizedData = normalize(preformattedData, [ sport ]);
Demo: https://codesandbox.io/s/20onxowzwn
I think this is what you need
const odd = new schema.Entity('odds');
const player = new schema.Entity('players' , { odds: [ odd]});
const match = new schema.Entity('matchs', {players: [player]});
but the result will be different because your json it is structured like this, I mean, the odds key is child of players, not of matches, therefore the result will be this way.
Just take a look at the console
Here is a solution with latest version of normalizr
const odds = new schema.Entity("odds");
const players = new schema.Entity("players", {
odds: [odds]
});
const matches = new schema.Entity("matches", { players: [players] });
const normalizedData = normalize(data, [matches]);
It would group data in your question as
{
"entities": {
"odds": {
"1": {
"id": 1,
"bookie_1": 1.6
}
},
"players": {
"22": {
"id": 22,
"name": "Rafa Nadal",
"country": "Spain",
"odds": [
1,
2,
3
]
}
},
"matches": {
"10689": {
"id": 10689,
"sport": "Tennis",
"players": [
22,
23
]
}
}
},
"result": [
10689
]
}
You can achieve your desired result by tweaking the process and merge strategies. I don't have time to do the leg work for you, but I explain the approach in detail here:
https://medium.com/#JustinTRoss/normalizing-data-into-relational-redux-state-with-normalizr-47e7020dd3c1

Categories

Resources