Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 4 years ago.
Improve this question
I have an array of arrays (2d array), and I want to convert it into an array of objects. In the resulting array, I would like each object to have a key-name (see expected output below)
data = [
['Apple', 'Orange', 'Banana', 'Pears', 'Peach'],
[40, 35, 25, 58, 84],
[2, 4, 4, 3, 1, 2],
['Red', 'Yellow', 'Green', 'Violet', 'Blue']
];
My expected result:
expected_result = [
{name: 'Apple', price: 40, quantity: 2, color: 'Red'},
{name: 'Orange', price: 35, quantity: 4, color: 'Yellow'},
{name: 'Banana', price: 25, quantity: 4, color: 'Green'},
{name: 'Pears', price: 58, quantity: 1, color: 'Violet'},
{name: 'Peach', price: 84, quantity: 2, color: 'Blue'}
];
Note The iteration of each array (in data) should be consecutive so that it gives the expected result
Seems to be there is one item extra in the quantity values. I have updated
[2, 4, 4, 3, 1, 2] to [2, 4, 4, 1, 2] removed 3 to match the result, hoping its a typo.
let data = [
["Apple", "Orange", "Banana", "Pears", "Peach"],
[40, 35, 25, 58, 84],
[2, 4, 4, 1, 2],
["Red", "Yellow", "Green", "Violet", "Blue"]
];
let output = [];
let props = ["name", "price", "quantity", "color"];
function updateInfo(row, prop){
row.filter((value, index) => {
if (output[index]) {
output[index][prop] = value;
} else {
output.push({
[prop]: value
});
}
});
};
data.filter((row, index) => {
updateInfo(row, props[index]);
});
console.log(output);
One solution consist of creating first a Map between the outter-array indexes and the property (or key) name you want to assign to them (however this could be replaced by an array like this ["name","price","quantity","color"]). Also, you can obtain the minimun length of the inner arrays to later check for non-creation of objects that won't have all the properties. After you do this pre-initialization, you can use Array.reduce() to generate your expected result:
const data = [
['Apple', 'Orange', 'Banana', 'Pears', 'Peach'],
[40, 35, 25, 58, 84],
[2, 4, 4, 3, 1, 2],
['Red', 'Yellow', 'Green', 'Violet', 'Blue']
];
let mapIdxToProp = new Map([[0, "name"],[1, "price"],[2, "quantity"],[3, "color"]]);
let minLen = Math.min(...data.map(x => x.length));
let res = data.reduce((acc, arr, idx) =>
{
arr.forEach((x, j) =>
{
(j < minLen) && (acc[j] = acc[j] || {}, acc[j][mapIdxToProp.get(idx)] = x);
});
return acc;
}, []);
console.log(res);
The simplest (not most efficient) solution in my opinion is to simply loop through the array, adding to another array as you go.
let arr = [
['Apple', 'Orange', 'Banana', 'Pears', 'Peach'],
[40, 35, 25, 58, 84],
[2, 4, 4, 1, 2],
['Red', 'Yellow', 'Green', 'Violet', 'Blue']
];
let keys = ["name", "price", "quantity", "color"];
let output = [];
//Add's blank objects too the output array
for (let i = 0; i < arr[0].length; i++) {
output.push({});
}
//Loops through the array
for (let i = 0; i < arr.length; i++) {
//Loops through the sub array
for (let x = 0; x < arr[i].length; x++) {
//Adds the sub array to the key that corresponds to it
output[x][keys[i]] = arr[i][x];
}
}
console.log(output);
Related
I have an object of filters.
filters = {color: 'black', size: '40'}
i want to return a filtered array of my data. Here's a sample of my data:
data = [
{
id: 1,
name: "Good Engine001"
categories: ['machine'],
color: ['Black', 'white'],
size: [30, 40, 50]
},
{
id: 2,
name: "Good Plane"
categories: ['machine', 'plane'],
color: ['Grey', 'white'],
size: [10, 30, 50]
},
{
id: 3,
name: "Good Chair001"
categories: ['furniture', 'chair'],
color: ['Brown', 'Black'],
size: [3, 5, 40]
}
];
filteredProducts = data.filter((item) =>
Object.entries(filters).every(([key, value]) =>
item[key].includes(value)
)
I'm quite stuck here. I am trying to set the filtered products to be equal to the few entries that matches with the values provided in my filters object. what am i doing wrong?
I was expecting this:
filteredProducts = [
{
id: 1,
name: "Good Engine001"
categories: ['machine'],
color: ['Black', 'white'],
size: [30, 40, 50]
},
{
id: 3,
name: "Good Chair001"
categories: ['furniture', 'chair'],
color: ['Brown', 'Black'],
size: [3, 5, 40]
}
];
But i got the same data.
If you want to compare case-insensitively and loosely compare numbers to their string equivalents, you won't be able to use Array.prototype.includes() since it uses strict comparisons.
Instead, you'll need to use Array.prototype.some() and compare stringified values using base sensitivity...
// Your data with typos fixed and minified
const data = [{"id":1,"name":"Good Engine001","categories":["machine"],"color":["Black","white"],"size":[30,40,50]},{"id":2,"name":"Good Plane","categories":["machine","plane"],"color":["Grey","white"],"size":[10,30,50]},{"id":3,"name":"Good Chair001","categories":["furniture","chair"],"color":["Brown","Black"],"size":[3,5,40]}]
// Stringifies values and compares with "base" sensitivity
const comparator = (dataValue, filterValue) =>
dataValue
.toString()
.localeCompare(filterValue, undefined, { sensitivity: "base" }) === 0;
// Checks various data types using the above comparator
const predicate = (dataValue, filterValue) => {
// Check arrays
if (Array.isArray(dataValue)) {
return dataValue.some((value) => comparator(value, filterValue));
}
// Exclude nested objects and null
if (typeof dataValue !== "object") {
return comparator(dataValue, filterValue);
}
return false;
};
const filters = { color: "black", size: "40" };
const filteredProducts = data.filter((item) =>
Object.entries(filters).every(([key, value]) => predicate(item[key], value))
);
console.log(filteredProducts);
.as-console-wrapper { max-height: 100% !important; }
color names are capital in data while they are not in filter.
'40' is string literal in filter, while it is number in your data.
and also your data should be like this with curly braces around each item:
const data = [
{
id: 1,
name: "Good Engine001",
categories: ['machine'],
color: ['Black', 'white'],
size: [30, 40, 50]
},
{
id: 2,
name: "Good Plane",
categories: ['machine', 'plane'],
color: ['Grey', 'white'],
size: [10, 30, 50]
},
{
id: 3,
name: "Good Chair001",
categories: ['furniture', 'chair'],
color: ['Brown', 'Black'],
size: [3, 5, 40]
}
];
This question already has answers here:
Zip arrays in JavaScript?
(5 answers)
Closed 3 months ago.
I am having two arrays,
the first array contains:
1, 2, 3, 4, 5
and the second one contains:
100, 200, 300, 400, 500
the result should be:
[ [ '1', '100' ],
[ '2', '200' ],
[ '3', '300' ],
[ '4', '400' ],
[ '5', '500' ] ]
You can loop through the array assuming they are the same size. toString() will give you the strings you want.
const first = [1, 2, 3, 4, 5]
const second = [100, 200, 300, 400, 500]
var result= [];
for(var i=0; i<first.length; i++){
result.push([first[i].toString(), second[i].toString()]);
}
console.log(result);
If arrays are not the same size and you only want while values exist in both indexes you could check for null or undefined.
const first = [1, 2, 3, 4, 5, 600, 700, 800]
const second = [100, 200, 300, 400, 500, 600, 700]
var result= [];
for(var i=0; i<first.length; i++){
if(first[i] && second[i]){
result.push([first[i].toString(), second[i].toString()]);
}
}
console.log(result);
Simply With forEach method:
const a = [1, 2, 3, 4, 5]
const b = [100, 200, 300, 400, 500]
const c = [];
a.forEach((el, ind) => {
c.push([el+"", b[ind]+""])
});
console.log(c)
Or with reduce method:
const a = [1, 2, 3, 4, 5]
const b = [100, 200, 300, 400, 500]
const c = a.reduce((acc, curr, ind) => {
acc.push([curr+"", b[ind]+""]);
return acc;
}, []);
console.log(c)
Tip: +"" is like doing .toString() will convert number into text
I have a loop that creates arrays like so but I want to find a way for grouping them from the fist values below I have show how the data is and the result I want how do I get the result from the data I have now.
['Brand', 'Workout', 12]
['Colour', 'Pink', 41]
['Fit', 'Regular', 238]
['Size', '10', 21]
['Type', 'T-Shirt', 139]
['Colour', 'Black', 71]
['Brand', 'Matalan', 13]
Brand: {
Workout: 12,
Matalan: 13
},
Colour: {
Pink: 41,
Black: 71
},
Fit: {
Regular: 238
},
Size: {
10: 21
},
Type: {
T-Shirt: 139
}
You can use Array.prototype.reduce for that. What you want to do is, put your input arrays into an array, which creates a two-dimensional array.
After that is done, use Array.prototype.reduce to accumulate an object, and split the input: ['Brand', 'Workout', 12] into the parameters: [key, property, value].
const input = [
['Brand', 'Workout', 12],
['Colour', 'Pink', 41],
['Fit', 'Regular', 238],
['Size', '10', 21],
['Type', 'T-Shirt', 139],
['Colour', 'Black', 71],
['Brand', 'Matalan', 13]
];
const result = input.reduce((accumulator, [key, property, value]) => {
accumulator[key] = {
...(accumulator[key] ?? {}),
[property]: value
};
return accumulator;
}, {});
console.log(result);
I have an array for example :
var array = [
[ 1, "Hello", "red", 0, "yes"],
[ 2, "Hello", "red", 1, "no"],
[ 3, "Hello", "blue", 4, "no"],
[ 4, "Sunshine", "yellow", 5, "yes"],
[ 5, "Hello", "red", 6, "yes"],.....]
Now I want to remove array based on multiple column lets say (2,3,5):
so based on 3 column I want to remove duplicates and keep first occurrence. my result should be like:
array = [[ 1, "Hello", "red", 0, "yes"],
[ 2, "Hello", "red", 1, "no"],
[ 3, "Hello", "blue", 4, "no"],
[ 4, "Sunshine", "yellow", 5, "yes"],....]
you see hello, red & yes matched. in column 2,3,5 so the first occurrence was only kept rest was removed. now I can not figure it out how to solve this complex issue.
function pullgm() {
// ss = SpreadsheetApp.getActiveSpreadsheet()
// sh2 = ss.getSheetByName("GP")
// sh3 = ss.getSheetByName("GM")
// var lr2 = sh2.getLastRow()
// var lc2 = sh2.getLastColumn()
// var lr3 = sh3.getLastRow()
// var lc3 = sh3.getLastColumn()
var array = [
[1, 'Hello', 'red', 0, 'yes'],
[2, 'Hello', 'red', 1, 'no'],
[3, 'Hello', 'blue', 4, 'no'],
[4, 'Sunshine', 'yellow', 5, 'yes'],
[5, 'Hello', 'red', 6, 'yes'],
];
var hash = Object.create(null),
length = array.length,
result = [],
element,
i,
key,
ref;
for (i = 0; i < length; i++) {
element = array[i];
key = array[i][0] + '|' + array[i][1] + '|' + array[i][6];
ref = hash[key];
if (ref) {
continue;
}
hash[key] = element.slice();
result.push(hash[key]);
}
console.log(array);
}
pullgm();
You could take a Set with a function which builds a key of the wanted indices.
After checking the set with the combined key, add either the key and return the actual data set or discard the actual array.
const
uniqueBy = (fn, s = new Set) => o => (k => !s.has(k) && s.add(k))(fn(o)),
key = keys => o => keys.map(k => o[k]).join('|'),
data = [[1, "Hello", "red", 0, "yes"], [2, "Hello", "red", 1, "no"], [3, "Hello", "blue", 4, "no"], [4, "Sunshine", "yellow", 5, "yes"], [5, "Hello", "red", 6, "yes"]],
result = data.filter(uniqueBy(key([1, 2, 4])));
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
I have a 2d this array with few values. I want to count the duplicates in this array and get a new 2d array with the values and in the end the number of counts
let colors = [
['blue', 'green', 5.00, 57],
['blue', 'green', 5.00, 57],
['yellow', 'green', 8.30, 84],
['blue', 'green', 5.00, 57],
['orange', 'blue', 7.00, 0],
['yellow', 'green', 8.30, 84],
];
function count_duplicate() {
let counts = []
for (let i = 0; i < colors.length; i++) {
if (counts[colors[i]]) {
counts[colors[i]] += 1
} else {
counts[colors[i]] = 1
}
}
console.log(counts);
}
count_duplicate();
now ich have this result
counts = [blue,green,5,57: 3, yellow,green,8.3,84: 2, orange,blue,7,0: 1]
but i need the array like this
counts = [[blue,green,5,57,3],
[yellow,green,8.3,84,2],
[orange,blue,7,0,1]]
change from array [] to an object {}, to easly manipulate each sub-array(row) how many times occures, it should be an object not an array!
and Using Object.entries looping through its key(str) and value(times), and return str splitted by comma and their times of occurences.
let colors = [
["blue", "green", 5.0, 57],
["blue", "green", 5.0, 57],
["yellow", "green", 8.3, 84],
["blue", "green", 5.0, 57],
["orange", "blue", 7.0, 0],
["yellow", "green", 8.3, 84],
];
function count_duplicate() {
let counts = {};//<--
for (let i = 0; i < colors.length; i++) {
if (counts[colors[i]]) {
counts[colors[i]] += 1;
} else {
counts[colors[i]] = 1;
}
}
console.log(counts); //{ 'blue,green,5,57': 3, 'yellow,green,8.3,84': 2, 'orange,blue,7,0': 1 }
const res = Object.entries(counts).map((count) => {
[str, times] = count; //['blue,green,5,57': 3]
return [...str.split(","), times];//[ 'blue', 'green', '5', '57', 3 ]
});
console.log(res);
}
count_duplicate();
Result:
[ [ 'blue', 'green', '5', '57', 3 ],
[ 'yellow', 'green', '8.3', '84', 2 ],
[ 'orange', 'blue', '7', '0', 1 ] ]
You can use Map here to achieve the result:
let colors = [
["blue", "green", 5.0, 57],
["blue", "green", 5.0, 57],
["yellow", "green", 8.3, 84],
["blue", "green", 5.0, 57],
["orange", "blue", 7.0, 0],
["yellow", "green", 8.3, 84],
];
function count_duplicate() {
let counts = new Map();
for (let i = 0; i < colors.length; i++) {
const data = counts.get(colors[i].toString());
if (data) data.count++;
else counts.set(colors[i].toString(), { value: colors[i], count: 1 });
}
const result = [];
for (let [, { value, count }] of counts) {
result.push([...value, count]);
}
return result;
}
console.log(count_duplicate());
I don't know about fancy syntax but using a hashmap should work which is just a JavaScript object.
let colors = [
['blue', 'green', 5.00, 57],
['blue', 'green', 5.00, 57],
['yellow', 'green', 8.30, 84],
['blue', 'green', 5.00, 57],
['orange', 'blue', 7.00, 0],
['yellow', 'green', 8.30, 84],
];
const hashmap = {};
colors.forEach(color => {
const key = JSON.stringify(color);
if(!hashmap[key]) hashmap[key] = 1;
else hashmap[key]++;
if(hashmap[key] == 1) return color;
});
console.log(hashmap);
const uniqueArray = [];
for(const key in hashmap)
uniqueArray.push(JSON.parse(key));
console.log(uniqueArray);
You're getting that output because the environment you're using is automatically coercing the array to a string. For example, Chrome and NodeJS do this, Firefox doesn't.
Here's a simple approach that uses an object to store data the updated color information in key/value pairs. It uses toString on the array for the key, and an array as the value comprising the original array, and an initialised total. The output (all the arrays stored as property values in the object) can then be extracted with Object.values.
let colors=[["blue","green",5,57],["blue","green",5,57],["yellow","green",8.3,84],["blue","green",5,57],["orange","blue",7,0],["yellow","green",8.3,84]];
const out = {};
colors.forEach(arr => {
// Create the key from the stringified array
const key = arr.toString();
// If the output object doesn't have a
// property with that key create one with
// an array built from the array, and setting
// the total to zero
out[key] = out[key] ?? [ ...arr, 0 ];
// Increment the total (the last element)
out[key][arr.length]++;
});
// Use Object.values to retrieve
// the updated arrays
console.log(Object.values(out));
Additional documentation
Spread syntax
Nullish coalescing operator