Restructuring Javascript Arrays - javascript

EDIT: Thanks for the replies!
I am kind of new to working with Javascript (sorry for probably the bad code). I've mainly only worked with HTML and CSS. I have been trying to experiment with Javascript, but I've been stuck on this forever. The outcome is not what I want it to be.
My code:
I want to make the array easier to use, by putting the values under the same category, but my code's output is not exactly what I want it to be like.
var data = {
idName: "idName",
valueRanges: [{
range: "range",
majorDimension: "ROWS",
values: [
[
"ID",
"Category",
"Name"
],
[
"1",
"Category1",
"Name1"
],
[
"2",
"Category1",
"Name2"
],
[
"3",
"Category2",
"Name3"
],
[
"4",
"Category1",
"Name4"
]
]
}]
}
var rows = [];
let batchRowValues = data.valueRanges[0].values
for (let i = 1; i < batchRowValues.length; i++) {
let rowObject = {};
for (let j = 0; j < batchRowValues[i].length; j++) {
rowObject[batchRowValues[0][j]] = batchRowValues[i][j];
}
rows.push(rowObject);
}
var newArray = rows.reduce(function(acc, curr) {
var findIfNameExist = acc.findIndex(function(item) {
return item.Category === curr.Category;
})
if (findIfNameExist === -1) {
let obj = {
'Category': curr.Category,
'value': [curr]
}
acc.push(obj)
} else {
acc[findIfNameExist].value.push(curr)
}
return acc;
}, []);
console.log('------------')
console.log('input: ' + JSON.stringify(data, null, 2))
console.log('------------')
console.log('output: ' + JSON.stringify(newArray, null, 2))
My code's output:
[
{
Category: "Category1",
value: [
{
Category: "Category1",
ID: "1",
Name: "Name1"
},
{
Category: "Category1",
ID: "2",
Name: "Name2"
},
{
Category: "Category1",
ID: "4",
Name: "Name4"
}
]
},
{
Category: "Category2",
value: [
{
Category: "Category2",
ID: "3",
Name: "Name3"
}
]
}
]
How I want it to look:
[
{
Category: "Category1",
values: [
{
ID: "1",
Name: "Name1"
},
{
ID: "2",
Name: "Name2"
},
{
ID: "4",
Name: "Name4"
}
]
},
{
Category: "Category2",
values: [
{
ID: "3",
Name: "Name3"
},
]
},
]
I want to learn! I appreciate any help.

You can use reduce.
Here idea is
Create a object and use category as key
If a category is already found than push the desired object in it's value property. if not than we create a new one with suitable data.
I am using object here instead of array directly is because i can directly access element using key where as in array i need to loop through each time and check existence of value
var data = {idName: "idName",valueRanges: [{range: "range",majorDimension: "ROWS",values: [["ID","Category","Name"],["1","Category1","Name1"],["2","Category1","Name2"],["3","Category2","Name3"],["4","Category1","Name4"]]}]}
var rows = [];
let batchRowValues = data.valueRanges[0].values.slice(1,)
let op = batchRowValues.reduce((op,[ID,Category,Name]) => {
if( op[Category] ){
op[Category].value.push({ID,Name})
} else {
op[Category] = {
Category,
value: [{ID,Name}]
}
}
return op
},{})
console.log(Object.values(op))

Try (t={}, result in r)
data.valueRanges[0].values.slice(1).map( ([i,c,n])=>
(t[c]=t[c]||{Category:c,values:[]}, t[c].values.push({ID:i, Name:n})) );
let r= Object.values(t);
var data =
{
idName: "idName",
valueRanges: [
{
range: "range",
majorDimension: "ROWS",
values: [
[
"ID",
"Category",
"Name"
],
[
"1",
"Category1",
"Name1"
],
[
"2",
"Category1",
"Name2"
],
[
"3",
"Category2",
"Name3"
],
[
"4",
"Category1",
"Name4"
]
]
}
]
}
let t={};
data.valueRanges[0].values.slice(1).map( ([i,c,n])=>
(t[c]=t[c]||{Category:c,values:[]}, t[c].values.push({ID:i, Name:n})) );
let r= Object.values(t);
console.log(r);

Related

ES6 map.has is not a function when called in a reducer

I want to return an array of objects without any duplicate ids. If there are any, then take the first one we see. So, we should NOT see {id: "2", value: '10'}. Instead, the value should be "Italian". I have this code below, but I am getting an map.has is not a function error.
const arr1 = [{
id: "1",
value: "English"
},
{
id: "2",
value: "Italian"
}
];
const arr2 = [{
id: "2",
value: '10'
},
{
id: "3",
value: "German"
}
];
const concatArr = arr1.concat(arr2);
const mergedArr = [...concatArr.reduce((map, obj) => map.has(obj.id) ? "" : map.set(obj.id, obj), new Map()).values()];
console.log(mergedArr);
You need to always return a map not an empty string when the thing is already in the map.
const arr1 = [{
id: "1",
value: "English"
},
{
id: "2",
value: "Italian"
}
];
const arr2 = [{
id: "2",
value: '10'
},
{
id: "3",
value: "German"
}
];
const concatArr = arr1.concat(arr2);
const mergedArr = [...concatArr.reduce((map, obj) => map.has(obj.id) ? map : map.set(obj.id, obj), new Map()).values()];
console.log(mergedArr);
You can use array#reduce to uniquely identify each object with unique id in an object accumulator and then extract all values from this object using Object.values().
const arr1 = [{ id: "1", value: "English" }, { id: "2", value: "Italian" } ],
arr2 = [{ id: "2", value: '10' }, { id: "3", value: "German" } ],
result = Object.values(arr1.concat(arr2).reduce((r, o) => {
r[o.id] = r[o.id] || o;
return r;
},{}));
console.log(result);

Can I sort an array of objects based on a array of subarrays?

I would ask a question regarding sorting.
Let's say I have an array of objects:
let arrayToBeSorted = [
{
name:"name1",
id:"id1",
},
{
name:"name2",
id:"id2",
},
{
name:"name3",
id:"id3",
},
{
name:"name4",
id:"id4",
},
{
name:"name5",
id:"id5",
},
{
name:"name6",
id:"id6",
}];
And Let's say I have an array of sub arrays which each one is containing IDs string like that:
let sortArray = [["id2", "id1"], ["id5"], ["id6","id3","id4"]]
What I want to do is to sort the arrayToBeSorted based on the sortArray preserving each subarrays (in order to maintain an hermetic order)
This is the wanted result:
arrayToBeSorted = [
{
name:"name2",
id:"id2",
},
{
name:"name1",
id:"id1",
},
{
name:"name5",
id:"id5",
},
{
name:"name6",
id:"id6",
},
{
name:"name3",
id:"id3",
},
{
name:"name4",
id:"id4",
}];
EDIT: I tried to:
arrayToBeSorted.sort((a,b)=> for(var i=0; i<sortArray.length;i++)
{
sortArr.indexOf(a.item.id) - sortArr.indexOf(b.item.id)
});
I also thought of sorting by each array and the concat the sorted result, but no success...
Thanks!
You seem to be overcomplicating the sort operation here. Use sort() on arrayToBeSorted and get the indexOf each array element in a flat()tened copy of sortArray:
let arrayToBeSorted = [{
name: "name1",
id: "id1",
}, {
name: "name2",
id: "id2",
}, {
name: "name3",
id: "id3",
}, {
name: "name4",
id: "id4",
}, {
name: "name5",
id: "id5",
}, {
name: "name6",
id: "id6",
}];
let sortArray = [
["id2", "id1"],
["id5"],
["id6", "id3", "id4"]
];
console.log(arrayToBeSorted.sort((a, b) => sortArray.flat().indexOf(a.id) - sortArray.flat().indexOf(b.id)));
You could flat the array and build an object with wanted order and sort the array.
const
data = [{ name: "name1", id: "id1" }, { name: "name2", id: "id2" }, { name: "name3", id: "id3" }, { name: "name4", id: "id4" }, { name: "name5", id: "id5" }, { name: "name6", id: "id6" }],
sortArray = [["id2", "id1"], ["id5"], ["id6", "id3", "id4"]],
order = Object.fromEntries(sortArray.flat().map((k, i) => [k, i + 1]));
data.sort((a, b) => order[a.id] - order[b.id]);
console.log(data);
.as-console-wrapper { max-height: 100% !important; top: 0; }
You can use sort() based on a flattened sortArray using findIndex() or indexOf() as #esqew. You could also go a step further and pre-process sortArray and create an object ids as keys and indices of sortArray as values. Then the sort function would be based on the object as follows:
let arrayToBeSorted = [{
name: "name1",
id: "id1",
},
{
name: "name2",
id: "id2",
},
{
name: "name3",
id: "id3",
},
{
name: "name4",
id: "id4",
},
{
name: "name5",
id: "id5",
},
{
name: "name6",
id: "id6",
}
];
let sortArray = [["id2", "id1"], ["id5"], ["id6","id3","id4"]];
const flatO = Object.fromEntries( sortArray.flat().map((id,i) => [id,i]) );
const sortedArray = arrayToBeSorted.sort((a,b) => flatO[a.id] - flatO[b.id]);
console.log( sortedArray );
NOTE: This is equivalent to #NinaScholz's solution. Saw it just after I posted this. I have upvoted both #NinaScholz's and #esqew's solutions but I would take #NinaScholz's since the flat() method including the creation of the order object execute JUST ONCE.

filter object value using node js

Is there any way i can filter values which are present inside Object
[
{
id: "1",
name:"animal_image.jpg"
},
{
id: "2",
name:"fish_image.jpg"
},
{
id: "3",
name:"animal_doc.txt"
},{
id: "4",
name:"fish_doc.txt"
},
{
id: "4",
name:"flower_petals.jpg"
},
{
id: "5",
name:"plant_roots.jpg"
},
{
id: "6",
name:"human_image.jpg"
},
]
i want to filter all the name which contain_image.jpg so output look like this
output=
[ "human_image.jpg",
"anima_image.jpg",
"fish_image.jpg"
]
In this code snippet filtredData is an array of objects where the name includes _image.jpg and output is just an array of names containing _image.jpg
const data = [
{
id: "1",
name: "animal_image.jpg"
},
{
id: "2",
name: "fish_image.jpg"
},
{
id: "3",
name: "animal_doc.txt"
}, {
id: "4",
name: "fish_doc.txt"
},
{
id: "4",
name: "flower_petals.jpg"
},
{
id: "5",
name: "plant_roots.jpg"
},
{
id: "6",
name: "human_image.jpg"
},
]
const filtredData = data.filter(el => el.name.includes("_image.jpg"));
console.log(filtredData);
const output = filtredData.map(el => el.name);
console.log(output);
filter & map
const output = arr
.filter(x => x.name.endsWith('_image.jpg'))
.map(x => x.name);

Javascript/ES6 generate nested array from 1 level object

i do have an object coming from an API like this:
this.Variations = [
{
attributes: [
{name: "Cor", option: "Preto"},
{name: "Tamanho", option: "P"},
{name: "Tecido", option: "Algodao"},
],
id : 1
},
{
attributes: [
{name: "Cor", option: "Preto"},
{name: "Tamanho", option: "P"},
{name: "Tecido", option: "Elastano"},
],
id : 2
},
{
attributes: [
{name: "Cor", option: "Preto"},
{name: "Tamanho", option: "M"},
{name: "Tecido", option: "Algodao"},
],
id : 3
}, ...
and i have to generate a nested array from it, in order to create the experience i need, which is the user selecting attributes one by time, and loading the possible options.
I am struggling with this for a long time now and got nowhere.
I believe I need an array similar to that:
array['Preto']['P']['Algodao'] = info;
array['Preto']['P']['Elastano'] = info;
array['Preto']['M']['Algodao'] = info;
Any tips on how to do that?
Assuming that by info you meant id value, try this approach
var output = variations.map( s => ({ [s.attributes[0].option ] :
{ [s.attributes[1].option ] :
{ [ s.attributes[2].option] : s.id } } }) );
Demo
var variations = [{
attributes: [{
name: "Cor",
option: "Preto"
},
{
name: "Tamanho",
option: "P"
},
{
name: "Tecido",
option: "Algodao"
},
],
id: 1
},
{
attributes: [{
name: "Cor",
option: "Preto"
},
{
name: "Tamanho",
option: "P"
},
{
name: "Tecido",
option: "Elastano"
},
],
id: 2
},
{
attributes: [{
name: "Cor",
option: "Preto"
},
{
name: "Tamanho",
option: "M"
},
{
name: "Tecido",
option: "Algodao"
},
],
id: 3
}
];
var output = variations.map( s => ({ [s.attributes[0].option ] : { [s.attributes[1].option ] : { [ s.attributes[2].option] : s.id } } }) );
console.log( output );
This code works regardless of the number of items in attributes arrays:
var Variations = [
{
attributes: [
{name: "Cor", option: "Preto"},
{name: "Tamanho", option: "P"},
{name: "Tecido", option: "Algodao"},
{name: "Foo", option: "Bar"},
],
id : 1
},
{
attributes: [
{name: "Cor", option: "Preto"},
{name: "Tamanho", option: "P"},
{name: "Tecido", option: "Elastano"},
],
id : 2
},
{
attributes: [
{name: "Cor", option: "Preto"},
{name: "Tamanho", option: "M"},
{name: "Tecido", option: "Algodao"},
],
id : 3
}];
const getLevelValue = (rec, att, index) => index === rec.attributes.length - 1 ? rec.id : {},
getData = variations => variations.map(rec => rec.attributes.
reduce(({acc, current}, att, index) =>
(current = current ? current[att.option] = getLevelValue(rec, att, index) :
acc[att.option] = getLevelValue(rec, att, index), {acc, current}),
{acc: {}}).acc);
console.log(getData(Variations));
You could iterate the array and the attributes for a nested object and assign a value at the leaves.
var data = [{ attributes: [{ name: "Cor", option: "Preto" }, { name: "Tamanho", option: "P" }, { name: "Tecido", option: "Algodao" }], id: 1 }, { attributes: [{ name: "Cor", option: "Preto" }, { name: "Tamanho", option: "P" }, { name: "Tecido", option: "Elastano" }], id: 2 }, { attributes: [{ name: "Cor", option: "Preto" }, { name: "Tamanho", option: "M" }, { name: "Tecido", option: "Algodao" }], id: 3 }],
result = {};
data.forEach(function (a) {
a.attributes.reduce(function (r, b, i, bb) {
return r[b.option] = i + 1 === bb.length
? a.id
: r[b.option] || {};
}, result);
});
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }

Populate array compared to another array

I have these 2 arrays
var array1 = [{
id: "Test1",
value: "Beep"
}, {
id: "Test2",
value: "Meep"
}, {
id: "Test3",
value: "Sheep"
}];
var array2 = [{
id: "Test2"
}, {
id: "Test3"
}],
stuff2: [{
id: "Test1"
}, {
id: "Test3"
}],
stuff3: [{
id: "Test3"
}];
I am looking for a way to insert empty objects or null to the 2nd array so that the 2nd array looks something like this:
var array2 = [null, {
id: "Test2"
}, {
id: "Test3"
}],
stuff2: [{
id: "Test1"
}, null, {
id: "Test3"
}],
stuff3: [
null, null, {
id: "Test3"
}
];
This can't be ES6 since the code base I am working on it rather old (AngularJS 1.4).
I haven't been able to wrap my mind around this one. Any help is welcome.
I am making some assumptions about what you are actually trying to accomplish (based on your input and desired output). The idea is that for each key in the containing object (array as you called them), you check to see if the id of each element in the stuff, stuff2, etc. arrays is equal to the object's index in the array + 1. (i.e. stuff[0].id === "Test1"). If that is not the case, insert null into the array at that position and move forward. It would look like the following:
var array2 = {
stuff: [{
id: "Test2"
}, {
id: "Test3"
}],
stuff2: [{
id: "Test1"
}, {
id: "Test3"
}],
stuff3: [{
id: "Test3"
}]
};
function fillGaps(obj) {
var keys = Object.keys(obj);
keys.forEach(function (key) {
var arr = obj[key];
for(var i = 0; i < arr.length; i++) {
var id = arr[i].id;
if (id !== "Test" + (i+1)) {
arr.splice(i, 0, null);
}
}
});
return obj;
}
console.log(fillGaps(array2));

Categories

Resources