Sorry if this is a stupid question, but I'm learning JavaScript and was wondering if there was an easy way to sort 2 lists like the ones here:
var names=["item", "item2", "item3", "item4", "item5", "item6", "item7", "item8", "item9", "item10"];
var points=[12, 12345, 5765, 123, 3, 567765, 99, 87654, 881, 101];
How would I display the items from 'names' according to the corresponding value in 'points'? For example, for the above item6 would displayed first and item5 would be displayed last.
I don't know if it's easy enough, but you could make an array of objects, sort it by the value prop and just map to get only the name props.
let names = ["item", "item2", "item3", "item4", "item5", "item6", "item7", "item8", "item9", "item10"],
points = [12, 12345, 5765, 123, 3, 567765, 99, 87654, 881, 101],
res = names.map((v, i) => ({ name: v, val: points[i] }))
.sort((a, b) => b.val - a.val)
.map(v => v.name);
console.log(res);
Here's a somewhat lengthy solution (with a much more concise version below). The basic idea is to:
Sort the points array in descending order
Loop through the sorted array, and find each value's position in the original points array
Grab the corresponding item from the names array
Push the value into a new array
var names=["item", "item2", "item3", "item4", "item5", "item6", "item7", "item8", "item9", "item10"];
var points=[12, 12345, 5765, 123, 3, 567765, 99, 87654, 881, 101];
const sortedPoints = points.slice().sort(function(a, b) {
return b - a;
});
const sortedNames = [];
sortedPoints.forEach(function(val) {
const position = points.indexOf(val);
sortedNames.push(names[position]);
})
console.log(sortedNames)
For a more concise solution, following the same process above but taking advantage of some shortcuts:
const names = ["item", "item2", "item3", "item4", "item5", "item6", "item7", "item8", "item9", "item10"];
const points = [12, 12345, 5765, 123, 3, 567765, 99, 87654, 881, 101];
const sortedNames = points.slice().sort((a, b) => b - a).map(val => names[points.indexOf(val)]);
console.log(sortedNames)
Javascript doesn't have a zip function natively. But that is most of what you want to do here. A little utility library like underscore is pretty handy. You can view the annotated source if you just want to replicate a zip function yourself.
var zippedAndSorted = _.zip(names, points)
.sort(function(a, b) {
return b - a;
});
Then you can iterate over each pair:
zippedAndSorted.forEach(function(namePoint) {
console.log('Name: ' + namePoint[0] + ' Points: ' + namePoint[1]);
});
Related
Hi I am trying to get the union of array by comparing two array of objects, but the output is not as expected. I need to compare every element in a and b and I need to union the values from const a, but my current implementation is giving me the union of const b. Could anyone help me what I am doing wrong? Thanks in advance!
Current Implementation:
const a = [
{id: "123", desc:"ItemOne", prdID:"PR-01"},
{id: "124", desc:"ItemTwo", prdID:"PR-02"}
]
const b = [
{id: "123", desc:"ItemOne", prdID:"PR-01", tbc:"yes"},
{id: "124", desc:"ItemTwo", prdID:"PR-02", tbc:"yes"},
{id: "124", desc:"ItemTwo", prdID:"PR-02", tbc:"no"}
]
const Union = [...new Map([...a, ...b].map(ele => [ele.id, ele])).values()];
Above implementation is giving the result from b not from a. But I need result from A.
if I changed the position of and b inside union I am getting the expected output, but I should always give a first not b.
const Union = [...new Map([...b, ...a].map(ele => [ele.id, ele])).values()];
Above code is working as expected. But I shouldn't interchange the position
You need to take reduce to fill the map and check if the key exist and keep the value, if so.
const
a = [{ id: "123", desc:"ItemOne", prdID:"PR-01" }, { id: "124", desc:"ItemTwo", prdID:"PR-02" }],
b = [{ id: "123", desc:"ItemOne", prdID:"PR-01", tbc:"yes" }, { id: "124", desc:"ItemTwo", prdID:"PR-02", tbc:"yes" }, { id: "124", desc:"ItemTwo", prdID:"PR-02", tbc:"no" }],
union = Array.from([...a, ...b]
.reduce((m, o) => m.set(o.id, m.get(o.id) ?? o), new Map)
.values()
);
console.log(union);
.as-console-wrapper { max-height: 100% !important; top: 0; }
How to optimize this transformation from array to object with specific key?
I have this array that inside has other arrays, and I wanted to turn this array into an array of objects. I would like to do this without using this index, and the object would like it to have these specific keys. I'm new to javascript and I would like to know if the way I did it was the best way, or if I can use a Map or Reduce to do what I want.
const listaCesar = [["cesar", "1", 1], ["thiago", "2", 2], ["giuseppe", "3", 3]]
const dict = []
listaCesar.forEach(item => dict.push({name: item[0], id: item[1], age: item[2]}))
console.log(dict)
This code works and gives me the expected result, but I don't know if I did it in the best way
ExpectResult = [{name: "cesar", id: "1", age: "1"}, {name: "thiago", id: "2", age: "2"}, {name: "giuseppe", id: "3", age: "3"}]
your solution is not bad, but I think you want something more "Elegant" so you can reduce your function to something like this:
const dict = listaCesar.map(([name, id, age]) => ({ name, id, age }));
basically with [name, id, age] you are destructuring the inner array and using those same names in the object { name, id, age } you will create a key value object with those name as keys.
const listaCesar = [
["cesar", "1", 1],
["thiago", "2", 2],
["giuseppe", "3", 3]
]
const dict = []
listaCesar.forEach(item => dict.push({
name: item[0],
id: item[1],
age: item[2]
}))
console.log(dict);
console.log('////////////////////////////////////////');
const dict2 = listaCesar.map(([name, id, age]) => ({
name,
id,
age
}));
console.log(dict2);
if you want something more performant to avoid using another structure you can reuse the same array that you have following the same approach, in this case you do not return a new array instead you reuse the same index on the array to put your new object.
const listaCesar = [
["cesar", "1", 1],
["thiago", "2", 2],
["giuseppe", "3", 3]
]
listaCesar.forEach(([name, id, age], i) => {
listaCesar[i] = {
name,
id,
age
}
})
console.log(listaCesar);
One improvement you can do is use an array to keep names of properties and loop over it to create object, so that it becomes extensible
const listaCesar = [
["cesar", "1", 1],
["thiago", "2", 2],
["giuseppe", "3", 3]
]
const props = ['name', 'id', 'age', ]
const dict = listaCesar.map(item => props.reduce((a, b, i) => {
a[b] = item[i]
return a
}, {}))
console.log(dict)
Here is a sample of JSON data of fruit weights and prices:
let fruitData = [{"fruit":"apple","weight":12,"price":1.80},
{"fruit":"apple","weight":15,"price":2.00},
{"fruit":"apple","weight":10,"price":1.60},
{"fruit":"banana","weight":22,"price":3.00},
{"fruit":"banana","weight":24,"price":3.20}]
If I want to group by the "fruit" property and return mean "weight" and "price" values for each fruit, what do I do to achieve this? The end result would be something like:
aggFruitData = [{"fruit":"apple","weight":12.3333,"price":1.8},
{"fruit":"banana","weight":23,"price":3.1}]
The big hope is that the data can still be in an easy to manipulate form like JSON following the transformation. I know that SQL provides a groupby method, but I'm wondering if that is more efficient or if using native JS is more effective. Ideally, this could be something that could be scaled up, such as including another property to group by (maybe like month sold/month price was recorded). I'm open to using either vanilla JS methods or a library/framework meant to parse in this way— I just want efficiency with the project's execution
Using vanilla js:
let fruitData = [{
"fruit": "apple",
"weight": 12,
"price": 1.80
},
{
"fruit": "apple",
"weight": 15,
"price": 2.00
},
{
"fruit": "apple",
"weight": 10,
"price": 1.60
},
{
"fruit": "banana",
"weight": 22,
"price": 3.00
},
{
"fruit": "banana",
"weight": 24,
"price": 3.20
}
];
const aggregated = Object.values(fruitData.reduce((current, item) => {
if (!current[item.fruit]) {
current[item.fruit] = {
...item,
count: 1
};
} else {
const i = current[item.fruit];
i.weight = (i.weight * i.count + item.weight) / (i.count + 1);
i.price = (i.price * i.count + item.price) / (i.count + 1);
i.count++;
}
return current;
}, {})).map(({
fruit,
weight,
price
}) => ({
fruit,
weight,
price
}));
console.log(aggregated);
// [ { fruit: 'apple', weight: 12.333333333333334, price: 1.8 },
// { fruit: 'banana', weight: 23, price: 3.1 } ]
You could also use the lodash library (_.groupBy etc) functions for this. Note that the last .map is to strip out the count field only, but you may actually find it useful to have that!
I have an array like so:
var myarray = [
{"scaleId":"001","currentWeight":0.200}
{"scaleId":"002","currentWeight":0.300},
{"scaleId":"001","currentWeight":0.255},
{"scaleId":"002","currentWeight":0.000},
{"scaleId":"003","currentWeight":0.340},
]
and I want to retain the objects which have unique scaleId. So, for the above example, the output would like ( any random object can be retained if the scaleId is duplicate):
myarray = [
{"scaleId":"001","currentWeight":0.200}
{"scaleId":"002","currentWeight":0.300},
{"scaleId":"003","currentWeight":0.340},
]
I'm already using underscore library in my application, so I'm fine with the implementation using underscore. I had come up with a solution but it is not working as expected. So, any help will be great.
Maps and Sets are often the appropriate structures to maintain uniqueness. Here is a simple function that uses a Map to maintain a single unique value given a property name:
const uniqByProp = (prop) => (xs) =>
[... new Map (xs .map ((x) => [x [prop], x])) .values ()]
var myarray = [{scaleId: "001", currentWeight: 0.200}, {scaleId: "002", currentWeight: 0.300}, {scaleId: "001", currentWeight: 0.255}, {scaleId: "002", currentWeight: 0.000}, {scaleId: "003", currentWeight: 0.340}]
console .log (
uniqByProp ('scaleId') (myarray)
)
.as-console-wrapper {min-height: 100% !important; top: 0}
This version keeps the last matching value. If you want the first matching one, it would be only slightly more complex.
Use reduce and inside callback check if in accumulator object there is a key with same scaleId. If so then add the value to that key. Finally use Object.values to create an array of values
var myarray = [{
"scaleId": "001",
"currentWeight": 0.200
},
{
"scaleId": "002",
"currentWeight": 0.300
},
{
"scaleId": "001",
"currentWeight": 0.255
},
{
"scaleId": "002",
"currentWeight": 0.000
},
{
"scaleId": "003",
"currentWeight": 0.340
}
]
let data = myarray.reduce((acc, curr) => {
if (!acc[curr.scaleId]) {
acc[curr.scaleId] = curr
}
return acc;
}, {});
console.log(Object.values(data))
You can do it this way (if you are using ES6/ES2015 or later)
Using Set to filter unique scaleIds first and feeding a new array with the Array.find method
var myarray = [
{"scaleId":"001","currentWeight":0.200},
{"scaleId":"002","currentWeight":0.300},
{"scaleId":"001","currentWeight":0.255},
{"scaleId":"002","currentWeight":0.000},
{"scaleId":"003","currentWeight":0.340},
]
let scaleIds = [...new Set(myarray.map(item => item.scaleId))];
let filtered = []
scaleIds.forEach(scaleId => filtered.push(myarray.find(item => item.scaleId === scaleId)))
console.log(filtered)
You can also use Array.prototype.reduceRight() to simplify aggregation logic:
let myarray = [
{ scaleId: '001', currentWeight: 0.2 },
{ scaleId: '002', currentWeight: 0.3 },
{ scaleId: '001', currentWeight: 0.255 },
{ scaleId: '002', currentWeight: 0 },
{ scaleId: '003', currentWeight: 0.34 }
];
myarray = Object.values(
myarray.reduceRight(
(acc, cur) => (acc[cur.scaleId] = cur, acc),
{}
)
).reverse(); // optional if order of output matters to you
console.log(myarray);
or construct a Map from key-value pairs generated using Array.prototype.map():
let myarray = [
{ scaleId: '001', currentWeight: 0.2 },
{ scaleId: '002', currentWeight: 0.3 },
{ scaleId: '001', currentWeight: 0.255 },
{ scaleId: '002', currentWeight: 0 },
{ scaleId: '003', currentWeight: 0.34 }
];
myarray = Array.from(
new Map(
myarray.map(
val => [val.scaleId, val]
).reverse()
).values()
).reverse(); // optional if order of output matters to you
console.log(myarray);
We use Array.prototype.reverse() on the array passed to the constructor to ensure that the insertion order allows earlier values to take precedence over later values.
I have an array which is built from data dynamically, so it can change.
It's basically this:
["t1", "something", "bird", "dog", "cow", "fish"]
What I need to do is to count how many of them there are and create another array with the same amount of columns but all with the value of 1.
For example, if the array is:
["bird", "dog", "cow", "fish"]
then it creates an array of:
[1, 1, 1, 1]
If the array is:
["bird", "fish"]
then it creates an array of:
[1, 1]
How can I do this?
You can use the Array.prototype.map method:
var input = ["foo", "bar", "baz"];
var mapped = input.map(function () { return 1; });
Just create a new array of equal length and use the fill function.
var myArray = ["dog","cat","monkey"];
var secondArray = new Array(myArray.length).fill(1);
// es6
var array = ["t1", "something", "bird", "dog", "cow", "fish"]
array.map(() => 1); // => [1, 1, 1, 1, 1, 1]
// if you don't care if they are strings
'1'.repeat(array.length).split(''); //=> ["1", "1", "1", "1", "1", "1"]