How to sort an array from an object? - javascript

How to sort an array from an object ?
The code :
let A = [ { text: '故事', value: 'story', },
{ text: '诗歌', value: 'poetry', },
{ text: '励志', value: 'inspirational', }
];
// array B from backend**
let B = {
story: 2,
poetry: 34,
inspirational: 30,
};
I want to get this :
[
{ text: '诗歌', value: 'poetry', },
{ text: '励志', value: 'inspirational'},
{ text: '故事', value: 'story', },
];

Simply you can use JavaScript sort function.
Note: When sorting numbers, you can simply use the compact comparison:
Compact Comparison:: myArray.sort((n1,n2) => n1 - n2);
let A = [ { text: '故事', value: 'story', },
{ text: '诗歌', value: 'poetry', },
{ text: '励志', value: 'inspirational', }
];
// array B from backend**
let B = {
story: 2,
poetry: 34,
inspirational: 30,
};
A.sort((a, b) => B[b.value]-B[a.value] );
console.log(A);

You can use an arrow function in array.sort as a custom comparator. Sorting in reverse order is accomplished by indexing into the B object to retrieve the sort value for compared elements and subtracting a's value from b.
let A = [
{ text: '故事', value: 'story', },
{ text: '诗歌', value: 'poetry', },
{ text: '励志', value: 'inspirational', }
];
let B = {
story: 2,
poetry: 34,
inspirational: 30,
};
const sorted = A.sort((a, b) => B[b.value] - B[a.value]);
console.log(sorted);

You can use sort() to arrange the array elements. You can use Number.NEGATIVE_INFINITY as a default value if the value does not exist on B. This will put the undefined value last.
let A = [{"text":"诗歌","value":"poetry"},{"text":"励志","value":"inspirational"},{"text":"故事","value":"story"}];
let B = {"story":2,"poetry":34,"inspirational":30};
A.sort((x, y) => (B[y.value] || Number.NEGATIVE_INFINITY) - (B[x.value] || Number.NEGATIVE_INFINITY));
console.log(A);

Try this, it uses an arrow function and array.sort:
let A = [{
text: '故事',
value: 'story',
},
{
text: '诗歌',
value: 'poetry',
},
{
text: '励志',
value: 'inspirational',
}
];
// array B from backend**
let B = {
story: 2,
poetry: 34,
inspirational: 30,
};
A.sort((a, b) => B[b.value] - B[a.value]);
console.log(A);

Using the function Array.prototype.sort you can accomplish your desired output.
This B[bV] - B[aV] will return a value lesser than 0 or greater than 0 or equal to 0 which is what the function sort is expecting on to locate the elements at the specific index according to their value from object B.
let A = [{ text: '故事', value: 'story', }, { text: '诗歌', value: 'poetry', }, { text: '励志', value: 'inspirational', }],
B = { story: 2, poetry: 34, inspirational: 30};
A.sort(({value: aV}, {value: bV}) => B[bV] - B[aV]);
console.log(A);
.as-console-wrapper { max-height: 100% !important; top: 0; }

Related

JS Removing duplicates from Multidimensional array

I want to reduce the object to one when the label is the same, and sum its value, however, needs to avoid the object with both same values of label and value, here is the example:
let arr = [
{
label: "▲",
value: 5
},
{
label: "▲",
value: 10
},
{
label: "■",
value: 13
},
{
label: "●",
value: 4
},
{
label: "■",
value: 6
},
{
label: "■",
value: 6
},
]
let expectedResult = [
{
label: "▲",
value: 15
},
{
label: "■",
value: 19
},
{
label: "●",
value: 4
},
]
I tried to use let newArr = [...new Set(arr)], but it returned the same array.
You can make use of Array.reduce and Object.values and achieve the expected output.
let arr = [{label:"▲",value:5},{label:"▲",value:10},{label:"■",value:13},{label:"●",value:4},{label:"■",value:6},{label:"■",value:6},]
const getReducedData = (data) => Object.values(data.reduce((acc, obj) => {
if(acc[obj.label]) {
acc[obj.label].value += obj.value;
} else {
acc[obj.label] = { ...obj }
}
return acc;
}, {}));
console.log(getReducedData(arr));
.as-console-wrapper {
max-height: 100% !important;
}

summarize values of objects with same attribute name

I have an array filled with objects. The following example shows the structure of the objects.
let array = [
{
data: [{name:'a', value:20}, {name:'b', value:10}, {name:'c', value:5}]
},
{
data: [{name:'d', value:20}, {name:'a', value:10}, {name:'e', value:40}]
},
{
data: [{name:'b', value:30}, {name:'a', value:5}]
}
];
I'm trying to iterate through all the data values and summarize all the identical letters and sum up there values in a new array. So the new array should look like this:
let array = [{name:'a', value:35}, {name:'b', value:40}, {name:'c', value:5}, {name:'d', value:20}, {name:'e', value:40}];
This is my current approach but I don't get it to work.
let prevData = '';
let summarizedArray = [];
for(let i = 0; i < array.length; i++) {
for(let j = 0; j < array[i].data.length; j++) {
if(prevData === array[i].data[j].name) {
let summarized = {
name: array[i].data[j].name;
value: prevData.value + array[i].data[j].value;
}
summarizedArray.push(summarized);
}
prevData = array[i].data[j];
}
}
// Edited Example:
let array = [
{
data: [{name:'a', value1:20, value2:90, value3:'foo'},
{name:'b', value1:30, value2:20, value3:'boo'}]
},
data: [{name:'c', value1:5, value2:10, value3:'goo'},
{name:'a', value1:30, value2:20, value3:'foo'}]
},
{
];
The values should be bundled by same names. The values of Value1 and Value2 should be added up and Value3 is always the same for each name.
So the result should look like this:
let result = [{name:'a', value1:50, value2:110, value3:'foo'},
{name:'b', value1:30, value2:20, value3:'boo'},
{name:'c', value1:5, value2:10, value3:'goo'}
];
You could take a Map and collect all values. Later get an array of object of the collected values.
let array = [{ data: [{ name: 'a', value: 20 }, { name: 'b', value: 10 }, { name: 'c', value: 5 }] }, { data: [{ name: 'd', value: 20 }, { name: 'a', value: 10 }, { name: 'd', value: 40 }] }, { data: [{ name: 'b', value: 30 }, { name: 'a', value: 5 }] }],
result = Array.from(
array.reduce(
(m, { data }) => data.reduce(
(n, { name, value }) => n.set(name, (n.get(name) || 0) + value),
m
),
new Map
),
([name, value]) => ({ name, value })
);
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
For a more convoluted object, you could take single properties to add, after a check for the type.
var array = [{ data: [{ name: 'a', value1: 20, value2: 90, value3: 'foo' }, { name: 'b', value1: 30, value2: 20, value3: 'boo' }] }, { data: [{ name: 'c', value1: 5, value2: 10, value3: 'goo' }, { name: 'a', value1: 30, value2: 20, value3: 'foo' }] }],
result = Array.from(
array.reduce(
(m, { data }) => {
data.forEach(o => {
var temp = m.get(o.name);
if (!temp) {
m.set(o.name, temp = {});
}
Object.entries(o).forEach(([k, v]) => {
if (k === 'name') return;
if (typeof v === 'number') {
temp[k] = (temp[k] || 0) + v;
} else {
temp[k] = v;
}
});
});
return m;
},
new Map
),
([name, value]) => Object.assign({ name }, value)
);
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }

Optimize sorting an Array from another Array

I have two arrays, one containings some items, and another containings sorted ids of those items like so:
const items = [
{ id: 1, label: 'foo' },
{ id: 2, label: 'bar' },
{ id: 3, label: 'lorem' },
{ id: 4, label: 'ipsum' },
]
const sortedItemIds = [4, 3, 2, 1]
I want to have another array containing items sorted by their id like so:
const sortedItems = [
{ id: 4, label: 'ipsum' },
{ id: 3, label: 'lorem' },
{ id: 2, label: 'bar' },
{ id: 1, label: 'foo' },
]
Note that the order may not be whatever, not asc or desc
I made this piece of code, that works pretty well as it:
let sortedItems = []
sortedItemIds.map((itemId, index) => {
items.map(item) => {
if (item.id === itemId) {
sortedItems[index] = item
}
}
})
I feel like I may run into issues with a large array of items, due to the nested Array.map() functions
Is there a better way / best practice for this scenario?
You could create one object where keys are ids and then use that object get values by id.
const items = [{ id: 1, label: 'foo' },{ id: 2, label: 'bar' },{ id: 3, label: 'lorem' },{ id: 4, label: 'ipsum' }]
const sortedItemIds = [4, 3, 2, 1]
const obj = {}
items.forEach(o => obj[o.id] = o);
const sortedItems = sortedItemIds.map(e => Object.assign({}, obj[e]));
console.log(sortedItems)
You don't need the function map for doing this, just use the find Array.indexOf and Array.sort in order to sort it.
const items = [{ id: 1, label: 'foo' },{ id: 2, label: 'bar' },{ id: 3, label: 'lorem' },{ id: 4, label: 'ipsum' }],
sortedItemIds = [4, 3, 2, 1];
items.sort((a, b) => sortedItemIds.indexOf(a.id) - sortedItemIds.indexOf(b.id));
console.log(items);
.as-console-wrapper { max-height: 100% !important; top: 0; }

Create an array of objects from two different arrays

I am having to different arrays. For eg :
Array 1 is :
[536, 549]
Array 2 is :
[
{ text: "ABCD", value: 341 },
{ text: "WXYZ", value: 439 }
]
I want to create an object as:
[
{
fieldId: 536,
value: {
value: 341,
display_value: "ABCD"
}
},
{
fieldId: 549,
value: {
value: 439,
display_value: "WXYZ"
}
}
]
I have no idea how to do this. Thanks in advance. :)
const arr_1 = [536, 549]
const arr_2 = [{text: "ABCD", value: 341},{text: "WXYZ", value: 439}]
// with map
let new_arr = arr_2.map( (ele, index) => {
return {
fieldID: arr_1[index],
value: { value: ele.value, display_value: ele.text }
};
});
// with for loop
let new_arr2 = [];
for(let i = 0; i < arr_2.length; i++){
new_arr2.append({
fieldID: arr_1[i],
value: { value: arr_1[i].value, display_value: arr_1[i].text }
});
}
Documentation for map():
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/map
Documentation for arrays:
https://developer.mozilla.org/en-US/docs/Glossary/array
Documentation for objects:
https://developer.mozilla.org/de/docs/Web/JavaScript/Reference/Global_Objects/Object
Not sure if it is desired to have the numbers as string. You would have to use toString(). Also not sure if it should be a json string in the end, to get that use JSON.stringify()
const arr1 = [ 536, 549 ];
const arr2 = [
{ text: "ABCD", value: 341 },
{ text: "WXYZ", value: 439 }
];
const result = arr1.map((value, index) => ({
fieldId: value,
value: {
display_value: arr2[index].text,
value: arr2[index].value
}
}));
Here, result will hold the desired value.

Javascript compare multiple arrays of objects

How can I compare multiple arrays of objects and add new properties with the number of occurrences an object was found and the array indexes where the object was found?
The object comparison must be made by the name property.
Example:
var arrays = [
[
{
name: 'aa',
value: 1
},
{
name: 'ab',
value: 2
},
{
name: 'ac',
value: 3
},
{
name: 'aa',
value: 1
}
],
[
{
name: 'aa',
value: 1
},
{
name: 'ab',
value: 2
},
],
[
{
name: 'ac',
value: 3
},
{
name: 'aa',
value: 1
}
]
]
After execution the object from the above array should have these properties:
[
[
{
name: 'aa',
value: 1,
occurrences: 3,
where: [0, 1, 2]
},
{
name: 'ab',
value: 2,
occurrences: 2,
where: [0, 1]
},
{
name: 'ac',
value: 3,
occurrences: 2,
where: [0, 2]
},
{
name: 'aa',
value: 1,
occurrences: 3,
where: [0, 1, 2]
}
],
[
{
name: 'aa',
value: 1,
occurrences: 3,
where: [0, 1, 2]
},
{
name: 'ab',
value: 2,
occurrences: 2,
where: [0, 1]
}
],
[
{
name: 'ac',
value: 3,
occurrences: 2,
where: [0, 2]
},
{
name: 'aa',
value: 1,
occurrences: 3,
where: [0, 1, 2]
}
]
]
Basically I want to check if the object with a specific name property exists in the other arrays.
This is the solution that comes in my mind:
1. Loop through the array that has the most objects
2. Loop through each object
3. Loop through the other arrays and apply Array.prototype.find()
But this will take a lot of time since each of my array will have at least 500 objects...
You can use array#reduce to get the number of occurrences and the index of occurrences in an object.
Then, you can modify your object in the arrays by simply using Object.assign() and adding the where and occurrences property.
var arrays = [ [ { name: 'aa', value: 1 }, { name: 'ab', value: 2 }, { name: 'ac', value: 3 }, { name: 'aa', value: 1 } ], [ { name: 'aa', value: 1 }, { name: 'ab', value: 2 }, ], [ { name: 'ac', value: 3 }, { name: 'aa', value: 1 } ] ];
var result = arrays.reduce((res, arr, index) => {
arr.forEach(({name,value}) => {
res[name] = res[name] || {occurrences: 0};
res[name]['where'] = res[name]['where'] || [];
if(!res[name]['where'].includes(index)){
res[name]['where'].push(index);
res[name].occurrences += 1;
}
});
return res;
},{});
arrays.forEach(arr => arr.forEach(obj => Object.assign(obj, result[obj.name])));
console.log(arrays);
This looked like trivial reduce, until i noticed nested arrays ) so it's more like flatten + reduce, with memory.
Code below is doing what you need, just the prop names are short (as i type them on the phone):
let f = (ai, a,v,i,m) => {
if (!a[v.id]) {
a[v.id] = {id: v.id, v: v.name, count: 1, at: [ai]};
} else {
a[v.id].count += 1;
a[v.id].at.push(ai);
}
return a;
};
let r = [[{id: 'aa', value: 42}], [{id: 'ba', value: 11}, {id: 'aa', value: 42}]]
.reduce ((a, v, i) => v.reduce (f.bind (null, i),a), {});
console.log (r);
Code still visits each element in any array only once, so complexity is O(n), and there should not be a problem running it on arrays up to a million of total elements (e.g. 1000 arrays of 1000 elements, or 200 x 5000).

Categories