I want to get the largest object in an array of objects, the code I'm using works fine, but I wonder if there is a better way of doing the same. This is the code I'm using.
data=[
{group: "a", A: 65, N: 20},
{group: "b", R: 52},
{group: "c", N: 20, A: 2, R: 2},
{group: "d", R: 15, N: 12},
]
len = []
for (var i in data){
len.push(Object.keys(data[i]).length)
}
for (var i in data){
if (Object.keys(data[i]).length==Math.max.apply(null, len)){
subgroups = Object.keys(data[i]).slice(1).sort();
}
}
console.log(subgroups);
I think one loop is sufficient to do this.
var data=[
{group: "a", A: 65, N: 20},
{group: "b", R: 52},
{group: "c", N: 20, A: 2, R: 2},
{group: "d", R: 15, N: 12},
],
max = Object.keys(data[0]).length,
largestObj = data[0];
data.forEach(i=>{
if(Object.keys(i).length> max){
max = Object.keys(i).length;
largestObj = i;
}
});
console.log(max);
console.log(largestObj);
An example using Array.prototype.reduce
const [biggestObject] = data.reduce(
([acc, length], entry) => {
const len = Object.keys(entry).length;
return length > len ? [acc, length] : [entry, len];
},
[{}, 0]
);
To sort the whole array seems stupid, one loop is enough using reduce function
const { element } = data.reduce((agg, element) => {
const length = Object.keys(v).length
if (length > agg.length) {
return { element, length }
}
return agg
}, { element: null, length: 0 })
You can just sort the array using the criteria you used for filling the len array.
data.sort((x, y) => {
return Object.keys(y).length - Object.keys(x).length
});
Result:
0: {group: "c", N: 20, A: 2, R: 2}
1: {group: "a", A: 65, N: 20}
2: {group: "d", R: 15, N: 12}
3: {group: "b", R: 52}
Related
Suppose I have an object:
let array = [
{a: 1, b: 5, c: 9},
{a: 2, b: 6, c: 10},
{a: 3, b: 7, c: 11},
{a: 4, b: 8, c: 12}
];
then I have a dictionary:
const columns = [
{ key: 'a', value: 'a' },
{ key: 'b', value: 'b' },
]
I want to filter out properties that are not defined in columns.
I have tried
array.map((x) => ({"a": x.a, "b": x.b}))
Is there a way to use the data defined in columns instead of manually typing all the properties?
Desired output:
[
{
"a": 1,
"b": 5
},
{
"a": 2,
"b": 6
},
{
"a": 3,
"b": 7
},
{
"a": 4,
"b": 8
}
]
You could map entries and get the new objects.
let
array = [{ a: 1, b: 5, c: 9 }, { a: 2, b: 6, c: 10 }, { a: 3, b: 7, c: 11 }, { a: 4, b: 8, c: 12 }],
columns = [{ key: 'a', value: 'a' }, { key: 'b', value: 'b' }],
keys = columns.map(({ key }) => key),
result = array.map(o => Object.fromEntries(keys.map(k => [k, o[k]])));
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
You could use this.
This uses just an array to hold the desired columns because I don't get why you would use a dictionary with key and value being the same.
let array = [
{ a: 1, b: 5, c: 9 },
{ a: 2, b: 6, c: 10 },
{ a: 3, b: 7, c: 11 },
{ a: 4, b: 8, c: 12 },
];
const desiredColumns = ["a", "b"];
const transformed = array.map(item => {
const obj = {};
desiredColumns.forEach(col => {
if(col in item){
obj[col] = item[col];
}
})
return obj;
})
console.log(array);
console.log(transformed)
Another, slightly less direct way using map() and reduce():
Create an array with all the keys we'll keep
Reduce the array to get the desired result
Add current key + value if key keep array
const array = [{a: 1, b: 5, c: 9}, {a: 2, b: 6, c: 10}, {a: 3, b: 7, c: 11}, {a: 4, b: 8, c: 12} ];
const columns = [{ key: 'a', value: 'a' }, { key: 'b', value: 'b' }, ];
const toKeep = columns.map(({ key }) => key).flat();
const result = array.map(a =>
Object.keys(a)
.reduce((prev, cur) => (toKeep.includes(cur)) ? { ...prev, [cur]: a[cur] } : prev, {})
);
console.log(result);
Result:
[
{
"a": 1,
"b": 5
},
{
"a": 2,
"b": 6
},
{
"a": 3,
"b": 7
},
{
"a": 4,
"b": 8
}
]
so I have a data structure that looks like this :
data = {
a: [1, 2, 3, 4, 5],
b: ["a", "b", "c", "d", "e"],
c: ["123", "235423", "12312", "1231", "12312"],
d: ["aa", "bb", "cc", "dd", "ee"],
...
}
and I need to convert it into a following structure:
[
{ a: 1, b: "a", c: "123", d: "aa", ... },
{ a: 2, b: "b", c: "235423", d: "bb", ... },
{ a: 3, b: "c", c: "12312", d: "cc", ... },
{ a: 4, b: "d", c: "1231", d: "dd", ... },
{ a: 5, b: "a", c: "12312", d: "ee", ... },
]
the number of keys in data can vary, but the length of the values will always be same across all arrays, i.e. data[a].length === data[z].length will always be true.
My solution:
const doStuff = () => {
const result = [];
const keys = Object.keys(data);
if (!keys) return result;
const valuesLength = keys[0].length
const result = [];
for (let i = 0; i < valuesLength ; i++) {
const obj = {};
for (const key in data) {
obj[key] = data[key][i];
}
result.push(obj);
}
return result;
};
is using two for loops is not most effective one since the number of keys can be large, so i'm looking for a most optimal solution
You may traverse your source object keys (Object.keys()) with Array.prototype.reduce(), looping inner arrays with Array.prototype.forEach() and assigning corresponding property of resulting object:
const src = {a:[1,2,3,4,5],b:["a","b","c","d","e"],c:["123","235423","12312","1231","12312"],d:["aa","bb","cc","dd","ee"]},
result = Object
.keys(src)
.reduce((acc, key, i, keys) => {
src[key].forEach((v, j) => {
acc[j] = acc[j] || {}
acc[j][key] = v
})
return acc
}, [])
console.log(result)
.as-console-wrapper{min-height:100%;}
The solution is going to require two loops. One to go over the properties in the object, the other to loop over the array of values.
Personally I would use reduce and forEach for the two loops
const data = {
a: [1, 2, 3, 4, 5],
b: ["a", "b", "c", "d", "e"],
c: ["123", "235423", "12312", "1231", "12312"],
d: ["aa", "bb", "cc", "dd", "ee"]
}
const result = Object.entries(data).reduce((arr, [key, values]) => (
values.forEach((value, index) => {
arr[index] = {
...arr[index],
[key]: value
};
}),
arr), []);
console.log(result);
without the fat arrows and destructuring
var data = {
a: [1, 2, 3, 4, 5],
b: ["a", "b", "c", "d", "e"],
c: ["123", "235423", "12312", "1231", "12312"],
d: ["aa", "bb", "cc", "dd", "ee"]
};
var result = Object.entries(data).reduce(function(result, entry) {
var key = entry[0];
var arr = entry[1];
arr.forEach(function(value, index) {
result[index] = result[index] || {};
result[index][key] = value;
});
return result;
}, []);
console.log(result);
Please check the below code:
var data = {
a: [1, 2, 3, 4, 5],
b: ["a", "b", "c", "d", "e"],
c: ["123", "235423", "12312", "1231", "12312"],
d: ["aa", "bb", "cc", "dd", "ee"]
}
var anotherObjArray = [];
for(var i=0;i<data[Object.keys(data)[0]].length;i++){
let tempObj = {};
for(var j=0;j<Object.keys(data).length;j++){
tempObj[Object.keys(data)[j]] = data[Object.keys(data)[j]][i];
}
anotherObjArray.push(tempObj);
}
anotherObjArray is the final array for your requirement.
By assuming same length arrays, you could get the entries and reduce the array by mapping all values along with the object at the same index and the new property.
const
data = { a: [1, 2, 3, 4, 5], b: ["a", "b", "c", "d", "e"], c: ["123", "235423", "12312", "1231", "12312"], d: ["aa", "bb", "cc", "dd", "ee"] },
result = Object
.entries(data)
.reduce((r, [k, a]) => a.map((v, i) => ({ ...r[i], [k]: v })), []);
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
I want to give a fixed order to an array of javascript objects and I've trying with the answer of this post but they are pointing to the value, not the keys.
fixed_order = ['group','A,'N','R']
data=[
{group: "a", A: 8, N: 6}
{group: "b", N: 4, A: 20, R: 1}
{group: "c", A: 7}
]
I've try with something like this but doesn't work.
data.sort(function (a, b) {
return fixed_order.indexOf(a.keys()) - fixed_order.indexOf(b.keys());
});
the result shoulb be something like this:
data=[
{group: "a", A: 8, N: 6}
{group: "b", A: 20, N: 4, R: 1}
{group: "c", A: 7}
]
You should not attempt to put object properties in a specific order. Objects are better thought of as unordered collections of properties. Even though modern engines implement the order defined by recent EcmaScript specifications, it is not considered good practice to make your code rely on that.
Instead, change your inner data structure from plain objects to arrays. An array is the recommended data structure when order is important.
const fixedOrder = ['group', 'A', 'N', 'R'];
const data = [
[["group", "a"], ["A", 8], ["N", 6]],
[["group", "b"], ["N", 4], ["A", 20], ["R", 1]],
[["A", 7], ["group", "c"]]
];
for (const row of data) {
row.sort((a, b) => fixedOrder.indexOf(a[0]) - fixedOrder.indexOf(b[0]));
}
console.log(data);
Given A and B of different lengths:
A = [
{X: "a", Y: 5},
{X: "b", Y: 10},
{X: "c", Y: 15}
];
B = [
{X: "a", Z: 5},
{X: "d", Z: 10}
];
Produces the following array:
C = [
{X: "a", Y: 5, Z: 5},
{X: "b", Y: 10},
{X: "c", Y: 15},
{X: "d", Z: 10}
]
So where X is the same the keys that are not X are joined together. Since "a" shares Y and Z it is added together.
Only when X is the same are they joined.
On top of my head a messy solution would be:
C = A.concat(B);
// filter down C to remove duplicate X's
for (i = 0; i < C.length - 1; i++) {
for (j = 1; j < C.length; j++) {
if (C[i]['X'] == C[j]['X']) {
// concatenate the keys together and delete one pair
}
}
}
// keep on looping until no duplicates...
What would be a proper solution for this?
I'm confused about the requirement/question but I believe you want something like the following:
var A = [
{X: "a", Y: 5},
{X: "b", Y: 10},
{X: "c", Y: 15}
];
var B = [
{X: "a", Z: 5},
{X: "d", Z: 10}
];
var C = A.concat(B), temp = {}, result = [];
C.forEach(function(o, i) {
temp[o.X] = temp[o.X] || o;
for(var k in o) temp[o.X][k] = o[k];
});
for(var i in temp) result.push(temp[i]);
console.log(result);
If this is your desired result then it could be re-written in es-6 as well but I kept it simple depending on your code example.
I have some data in the format given below:
var data = [
{name: "A", rank: 0, c: 92},
{name: "B", rank: 45, c: 99},
{name: "C", rank: 89, c: 89},
{name: "D", rank: 23, c: 99},
{name: "E", rank: 56, c: 98}
];
I want to find a subset of this data like say only 3 values. I am not sure how to do this is d3js. The solutions I found were mainly based on the property of data like:
data = data.filter(function(d){return +d.rank < 10});
But this gives me all data points with rank < 10 but I want to limit the "size" of data (number of data points) based on some user input.
How can I do that?
May be like this using filter + slice:
var data = [
{name: "A", rank: 0, c: 92},
{name: "B", rank: 45, c: 99},
{name: "C", rank: 89, c: 89},
{name: "D", rank: 23, c: 99},
{name: "E", rank: 56, c: 98}
];
var size = 3; //user input size that is needed
var result = data.filter(function(d) {return (+d.rank > 10)}).slice(0,size)
console.log(result)