Related
Let's say I have an array of objects:
var list = [
{ name: "A", distance: 1},
{ name: "B", distance: 2},
{ name: "C", distance: 3},
{ name: "D", distance: 4},
{ name: "E", distance: 5},
{ name: "F", distance: 6},
{ name: "G", distance: 7},
{ name: "H", distance: 8}
];
if I have another array like this one :
var disturbed = ["G", "B", "C", "F"];
how can I sort disturbed array based on distance property from the list array like this:
["B", "C", "F", "G"];
Edit: I have tried this code with no success:
items = [
{ name: "A", distance: 1},
{ name: "B", distance: 2},
{ name: "C", distance: 3},
{ name: "D", distance: 4},
{ name: "E", distance: 5},
{ name: "F", distance: 6},
{ name: "G", distance: 7},
{ name: "H", distance: 8}
]
sorting = [ 1, 2,3,4,5,6,7,8,9,10 ];
result = []
for (let i = 0; i < items.length; i++){
sorting.forEach(function(key) {
var found = false;
items = items.filter(function(item) {
if(!found && items[i].distance == key) {
result.push(item);
found = true;
return false;
} else
return true;
})
})
result.forEach(function(item) {
document.writeln(item[i])
})
}
How can I Sort an array based on the property value of another array of objects
You can use .reduce() to change the list array to object and then sort based on this object.
Demo:
var list = [
{ name: "A", distance: 1},
{ name: "B", distance: 2},
{ name: "C", distance: 3},
{ name: "D", distance: 4},
{ name: "E", distance: 5},
{ name: "F", distance: 6},
{ name: "G", distance: 7},
{ name: "H", distance: 8}
];
var disturbed = ["G", "B", "C", "F"];
var sort = list.reduce((acc, cur) => {
acc[cur.name] = cur.distance;
return acc;
}, {});
disturbed.sort((a, b) => sort[a] - sort[b]);
console.log(disturbed)
You can use the sort method to do that
var list = [
{ name: "A", distance: 1},
{ name: "B", distance: 2},
{ name: "C", distance: 3},
{ name: "D", distance: 4},
{ name: "E", distance: 5},
{ name: "F", distance: 6},
{ name: "G", distance: 7},
{ name: "H", distance: 8}
];
var disturbed = ["G", "B", "C", "F"];
disturbed.sort((a, b) => {
var itemA = list.find(item => item.name === a);
var itemB = list.find(item => item.name === b);
return itemA.distance - itemB.distance;
});
disturbed.forEach(function(item) {
document.writeln(item[i])
})
You can use .find() to find the object with the specified name property that matches your elements in distributed. Once you have got this you can then get the distance property and calculate the difference to sort accordingly:
const list = [
{ name: "A", distance: 1},
{ name: "B", distance: 2},
{ name: "C", distance: 3},
{ name: "D", distance: 4},
{ name: "E", distance: 5},
{ name: "F", distance: 6},
{ name: "G", distance: 7},
{ name: "H", distance: 8}
];
const disturbed = ["G", "B", "C", "F"];
const res = disturbed.sort((a, b) => {
const {distance: d_a} = list.find(({name}) => name === a);
const {distance: d_b} = list.find(({name}) => name === b);
return d_a - d_b;
});
console.log(res);
A more efficient approach would be to create a new Map using .map() and then use .sort() on the keys form the map:
const list = [
{ name: "A", distance: 1},
{ name: "B", distance: 2},
{ name: "C", distance: 3},
{ name: "D", distance: 4},
{ name: "E", distance: 5},
{ name: "F", distance: 6},
{ name: "G", distance: 7},
{ name: "H", distance: 8}
];
const disturbed = ["G", "B", "C", "F"];
const lut = new Map(list.map(({name, distance}) => [name, distance]));
const res = disturbed.sort((a, b) => lut.get(a) - lut.get(b));
console.log(res);
I wanted to make an exception. It's hard for me to explain it, so let me show you what I mean.
My code:
fruits = [
{name: "apple", energy: 100, not: "kiwi"},
{name: "kiwi", energy: 126, not: "orange"},
{name: "banana", energy: 150, not: ""},
{name: "orange", energy: 118, not: "peach"},
{name: "pineapple", energy: 98, not: ""},
{name: "coconut", energy: 83, not: ""},
{name: "peach", energy: 65, not: ""},
{name: "lemon", energy: 36, not: ""}
]
const pick = (arr, n) => {
const r = [];
for (var i = 0; i < arr.length; i += n) {
const slice = arr.slice(i, i+n);
const name = slice.map(({name}) => name).join('-')
const energy = slice.reduce((r, {energy}) => r + energy, 0);
r.push({name, energy})
}
return r;
}
const result = pick(fruits, 2)
console.log(result)
The result I get is
{name: "apple-kiwi", energy: 226},
{name: "banana-orange", energy: 268},
{name: "pineapple-coconut", energy: 181},
{name: "peach-lemon", energy: 101}
What I want is to make an exception (not in fruits). So apple shouldn't link with kiwi, kiwi with orange, etc. and it should look like this
{name: "apple-banana", energy: something},
{name: "kiwi-pineapple", energy: something},
...
I thought I could filter slice and check if any of it's items contains not, but I failed :(
Could anyone help me?
You need to take an array of names and an array of exceptions, and check them at the intersection:
fruits = [
{name: "apple", energy: 100, not: "kiwi"},
{name: "kiwi", energy: 126, not: "orange"},
{name: "banana", energy: 150, not: ""},
{name: "orange", energy: 118, not: "peach"},
{name: "pineapple", energy: 98, not: ""},
{name: "coconut", energy: 83, not: ""},
{name: "peach", energy: 65, not: ""},
{name: "lemon", energy: 36, not: ""}
]
function intersect (a1, a2) {
var isIntersect = false
a1.forEach(function (a) {
if (a.length > 0 && a2.indexOf(a) !== -1) isIntersect = true
})
return isIntersect
}
const pick = (arr, n) => {
const r = [];
for (var i = 0; i < arr.length; i += n) {
const slice = arr.slice(i, i+n);
const namesArr = slice.map(({name}) => name)
const notsArr = slice.map(({not}) => not)
if (!intersect(namesArr, notsArr)) {
const name = namesArr.join('-')
const energy = slice.reduce((r, {energy}) => r + energy, 0);
r.push({name, energy})
}
}
return r;
}
const result = pick(fruits, 2)
console.log(result)
Actually what you need is to filter the array to select the elements that doesn't have not property's value equal to the iterated item name:
const pick = (arr, n) => {
const r = [];
for (var i = 0; i < arr.length; i += n) {
var slice = [];
slice.push(arr[i]);
slice = slice.concat(arr.filter(function(x, ind) {
return x.name !== arr[i].name && x.not !== arr[i].name
}));
slice = slice.slice(0, n);
var name = slice.reduce((r, {
name
}) => r + name + "-", "");
name = name.replace(/\-$/, '');
const energy = slice.reduce((r, {
energy
}) => r + energy, 0);
r.push({
name,
energy
});
}
return r;
}
Demo:
var fruits = [{
name: "apple",
energy: 100,
not: "kiwi"
},
{
name: "kiwi",
energy: 126,
not: "orange"
},
{
name: "banana",
energy: 150,
not: ""
},
{
name: "orange",
energy: 118,
not: "peach"
},
{
name: "pineapple",
energy: 98,
not: ""
},
{
name: "coconut",
energy: 83,
not: ""
},
{
name: "peach",
energy: 65,
not: ""
},
{
name: "lemon",
energy: 36,
not: ""
}
]
const pick = (arr, n) => {
const r = [];
for (var i = 0; i < arr.length; i += n) {
var slice = [];
slice.push(arr[i]);
slice = slice.concat(arr.filter(function(x, ind) {
return x.name !== arr[i].name && x.not !== arr[i].name
}));
slice = slice.slice(0, n);
var name = slice.reduce((r, {
name
}) => r + name + "-", "");
name = name.replace(/\-$/, '');
const energy = slice.reduce((r, {
energy
}) => r + energy, 0);
r.push({
name,
energy
});
}
return r;
}
const result = pick(fruits, 2)
console.log(result)
I have a problem with picking some data with array of objects and pushing it into new object (in different array), but in different way.
const fruits = [
{name: "apple"},
{name: "kiwi"},
{name: "banana"},
{name: "orange"},
{name: "pineapple"},
{name: "coconut"},
{name: "peach"},
{name: "lemon"}
]
I want to pick a few items from this and paste them into completely new array, so it could look like this:
const manyFruits = [
{name: "apple-banana-kiwi-coconut"},
{name: "orange-pineapple-peach-lemon"}]
It would be great to do a function which takes an argument of how many fruits we want to pick into new array and they shouldn't repeat.
Below is my code. Firstly I create new array with names, then I push them into new array which depends on "length" and finally I try to create new array with objects, but it fails.
const fruitArray = length => {
const fruits = [
{name: "apple"},
{name: "kiwi"},
{name: "banana"},
{name: "orange"},
{name: "pineapple"},
{name: "coconut"},
{name: "peach"},
{name: "lemon"}
]
const allFruits = []
for (let i = 0; i < fruits.length; i++) {
allFruits.push(fruits[i].name)
}
const newFruits =[]
for (let i = 0; i < length; i++) {
newFruits.push(allFruits[i])
}
const manyFruitsInOneArr = []
for (let i = 0; i < 2; i++) {
let newArr = {
name: newFruits.join("-"),
}
manyFruitsInOneArr[i] = (newArr)
}
console.log(manyFruitsInOneArr)
}
fruitArray(2)
It generates new objects in new array, but items are the same all the time.
You can create function for this using for loop and inside map() method to get array of names and join() to make a string from values.
const fruits = [{"name":"apple"},{"name":"kiwi"},{"name":"banana"},{"name":"orange"},{"name":"pineapple"},{"name":"coconut"},{"name":"peach"},{"name":"lemon"}]
const pick = (arr, n) => {
const r = [];
for (var i = 0; i < arr.length; i += n) {
const name = arr
.slice(i, i + n)
.map(({name}) => name)
.join('-');
r.push({name})
}
return r;
}
const result = pick(fruits, 2)
console.log(result)
Update: to get names and sum of energy for each slice you can use map() and reduce() methods.
fruits = [ {name: "apple", energy: 100}, {name: "kiwi", energy: 126}, {name: "banana", energy: 150}, {name: "orange", energy: 118}, {name: "pineapple", energy: 98}, {name: "coconut", energy: 83}, {name: "peach", energy: 65}, {name: "lemon", energy: 36} ]
const pick = (arr, n) => {
const r = [];
for (var i = 0; i < arr.length; i += n) {
const slice = arr.slice(i, i+n);
const name = slice.map(({name}) => name).join('-')
const energy = slice.reduce((r, {energy}) => r + energy, 0);
r.push({name, energy})
}
return r;
}
const result = pick(fruits, 2)
console.log(result)
That could be done using recursion:
function subset(arr, n){
if(!(n - 1)) return [arr[0].name];
const result = [];
for(let i = 0; i < arr.length - n; i++){
for(const sub of subset(arr.slice(i + 1), n - 1)){
result.push(arr[i].name + "-" + sub);
}
}
return result;
}
So you can do:
subset(fruits, 5);
Let's say I have a bar and cars stop by to pick up beer(s) before heading to the beach. Each car has a trunk size (remainingSum) and each beer has a size (beer.size)
I would like to provide customers with the beer combination choices (AllCombinations) that their car trunk can fit, but unique combinations.
For example, Input:
let Beers = [
{id: 1, size: 4},
{id: 5, size: 1},
{id: 10, size: 0.5},
{id: 11, size: 1},
{id: 12, size: 2},
{id: 13, size: 1},
];
let TrunkSize = 2;
Expected Output
AllCombinations = [ // no duplicates
[{id: 5, size: 1}, {id: 10, size: 0.5}],
[{id: 5, size: 1}, {id: 11, size: 1}],
[{id: 5, size: 1}, {id: 13, size: 1}],
[{id: 10, size: 0.5}, {id: 11, size: 1}],
[{id: 10, size: 0.5}, {id: 13, size: 1}],
[{id: 11, size: 1}, {id: 13, size: 1}],
[{id: 5, size: 1}],
[{id: 11, size: 1}],
[{id: 12, size: 2}],
[{id: 13, size: 1}],
[{id: 10, size: 0.5}],
]
Current Output
AllCombinations = [
[{id: 5, size: 1}, {id: 10, size: 0.5}], // dup a
[{id: 5, size: 1}, {id: 11, size: 1}], // dup c
[{id: 5, size: 1}, {id: 13, size: 1}], // dup d
[{id: 10, size: 0.5}, {id: 5, size: 1}], // dup a
[{id: 10, size: 0.5}, {id: 11, size: 1}], // dup b
[{id: 10, size: 0.5}, {id: 13, size: 1}], // dup e
[{id: 11, size: 1}, {id: 13, size: 1}], // dup f
[{id: 11, size: 1}, {id: 10, size: 0.5}], // dup b
[{id: 11, size: 1}, {id: 5, size: 1}], // dup c
[{id: 13, size: 1}, {id: 5, size: 1}], // dup d
[{id: 13, size: 1}, {id: 10, size: 0.5}], // dup e
[{id: 13, size: 1}, {id: 11, size: 1}], // dup f
[{id: 5, size: 1}],
[{id: 11, size: 1}],
[{id: 12, size: 2}],
[{id: 13, size: 1}],
[{id: 10, size: 0.5}]
]
Current function:
AllCombinations = [];
GetCombinations(currentCombination, beers, remainingSum)
{
if (remainingSum < 0)
return;// Sum is too large; terminate recursion
else {
if (currentCombination.length > 0)
{
currentCombination.sort();
var uniquePermutation = true;
for (var i = 0; i < this.AllCombinations.length; i++)
{
if (currentCombination.length == this.AllCombinations[i].length)
{
for (var j = 0; currentCombination[j] == this.AllCombinations[i][j] && j < this.AllCombinations[i].length; j++); // Pass
if (j == currentCombination.length) {
uniquePermutation = false;
break;
}
}
}
if (uniquePermutation)
this.AllCombinations.push(currentCombination);
}
}
for (var i = 0; i < beers.length; i++) {
var newChoices = beers.slice();
var newCombination = currentCombination.concat(newChoices.splice(i, 1));
var newRemainingSum = remainingSum - beers[i].size;
this.GetCombinations(newCombination, newChoices, newRemainingSum);
}
}
I've edited your code, fixing sort & checking with additional array & stringify:
let Beers = [
{id: 1, size: 4},
{id: 5, size: 1},
{id: 10, size: 0.5},
{id: 11, size: 1},
{id: 12, size: 2},
{id: 13, size: 1},
];
let TrunkSize = 2;
AllCombinations = [];
var combStrings = []
function GetCombinations(currentCombination, beers, remainingSum)
{
if (remainingSum < 0)
return;// Sum is too large; terminate recursion
else {
if (currentCombination.length > 0)
{
currentCombination.sort((a,b)=>{
return a.id > b.id
});
//var uniquePermutation = true;
var tmp = currentCombination.map((cc)=>{
return cc.id;
})
if (combStrings.indexOf(JSON.stringify(tmp)) == -1) {
this.AllCombinations.push(currentCombination);
var tmp = currentCombination.map((cc)=>{
return cc.id;
})
combStrings.push(JSON.stringify(tmp))
}
}
}
for (var i = 0; i < beers.length; i++) {
var newChoices = beers.slice();
var newCombination = currentCombination.concat(newChoices.splice(i, 1));
var newRemainingSum = remainingSum - beers[i].size;
this.GetCombinations(newCombination, newChoices, newRemainingSum);
}
}
GetCombinations([],Beers,TrunkSize)
console.log(AllCombinations,combStrings)
Here's another approach:
let Beers = [
{id: 1, size: 4},
{id: 5, size: 1},
{id: 10, size: 0.5},
{id: 11, size: 1},
{id: 12, size: 2},
{id: 13, size: 1},
];
let TrunkSize = 2;
// get all combinations (stolen from http://stackoverflow.com/questions/5752002/find-all-possible-subset-combos-in-an-array )
function combinations(array) {
return new Array(1 << array.length).fill().map(
(e1,i) => array.filter((e2, j) => i & 1 << j));
}
// filter them out if the summed sizes are > trunksize
var valids = combinations(Beers).filter(function(el) {
return el.reduce(function(a,b){return a+b.size;}, 0) <= TrunkSize;
});
console.log(valids);
To get all possible combinations without duplicates, you can represent your combinations with a set of N bits, where N = # of 🍺.
So you should get a table that looks like this:
000000
000001
000010
000011
000100
000101
000110
000111
...
111111
The 1 tell you which beers are part of that possible combination. Then you just sum their sizes. If you get a sum greater than trunkCapacity, abort that loop.
After the loop, check that the total size of that combination is within the limits and add it to the list of combinations.
function getCombination(beers, trunkSize) {
const beersCount = beers.length;
const combinationsCount = Math.pow(2, beersCount);
const combinations = [];
let i = 0; // Change this to 1 to remove the empty combination that will always be there.
while(i < combinationsCount) {
const binary = i.toString(2);
const bits = Array.prototype.concat.apply(Array(beersCount - binary.length).fill(0), binary.split('').map(parseInt));
const combination = [];
let bit = 0;
let total = 0;
while(bit < beersCount && total <= trunkSize) {
if (bits[bit]) {
const beer = beers[bit];
total += beer.size;
combination.push(beer);
}
++bit;
}
if (total <= trunkSize) {
combinations.push(combination)
}
++i;
}
return combinations;
}
const combinations = getCombination([
{id: 1, size: 4},
{id: 5, size: 1},
{id: 10, size: 0.5},
{id: 11, size: 1},
{id: 12, size: 2},
{id: 13, size: 1},
], 2);
console.log(JSON.stringify(combinations, null, 2));
You could get all combinations and decide which sets match the conditions.
function getCombinations(array, sum, length) {
function fork(i, t) {
var s = t.reduce((a, b) => a + b.size, 0);
if (i === array.length) {
return s <= sum && t.length <= length && result.push(t);
}
fork(i + 1, t.concat([array[i]]));
fork(i + 1, t);
}
var result = [];
fork(0, []);
return result;
}
var beers = [{ id: 1, size: 4 }, { id: 5, size: 1 }, { id: 10, size: 0.5 }, { id: 11, size: 1 }, { id: 12, size: 2 }, { id: 13, size: 1 }],
result = getCombinations(beers, 2, 2);
document.getElementById('out').appendChild(document.createTextNode(JSON.stringify(result, 0, 4)));
<pre id="out"></pre>
I have a stupid problem that at first seems to be simple to solve, but turns out to be tricky.
I have an array of objects, each with two properties: id and value:
[
{id: 2, value: 10},
{id: 4, value: 3},
{id: 2, value: 2},
{id: 1, value: 15}
]
I want to write an algorithm that sums up the values of ones with similar id.
My end result should be a new array with only the merged objects:
[
{id: 2, value: 12},
{id: 4, value: 3},
{id: 1, value: 15}
]
I've tried the following, but it doesn't work:
var arr = [];
arr.push({id: 2, visit:10});
arr.push({id: 4, visit:3});
arr.push({id: 2, visit:2});
arr.push({id: 1, visit:15});
// Deep copy
var copy = jQuery.extend(true, [], arr);
var masterArr = [];
for (var i = 0; i < arr.length; i++) {
var objArr = [];
objArr.push(arr[i]);
for (var j = copy.length-1; j > -1; j--) {
if (arr[i].id === copy[j].id) {
var q = copy.splice(j,1);
}
}
masterArr.push(objArr);
}
My plan was to first gather all similar objects in separate arrays (objArr), sum them up and put them in an end array (masterArr). I use jquerys extend to make a deep copy (not a reference) and reverse iteration and splice to remove objects thats already been found as "duplicates".
This doesn't work! And it doesn't seem to be a very efficient mehtod to solve my problem.
How could I do this? Performance isn't top priority but rather "nice to have"!
Thanks!
You can do it like this:
// Assuming:
a = [{id: 2, value: 10}, {id: 4, value: 3}, {id: 2, value: 2}, {id: 1, value: 15}]
var b = {}, // Temporary variable;
c = []; // This will contain the result;
// Build a id:value object ( {1: 15, 2: 12, 4: 3} )
a.map(function(current){b[current.id] = (b[current.id] || 0) + current.value});
for(var key in b){ // Form that into the desired output format.
c.push({id: parseInt(key, 10), value: b[key]});
}
console.log(c);
/* [{id: 1, value: 15},
{id: 2, value: 12},
{id: 4, value: 3}] */
I'm using parseInt(key, 10), since the keys are strings, you'll probably want them converted to integers again.
// First group the data based on id and sum the values
var temp = data.reduce(function(result, current) {
result[current.id] = (result[current.id] || 0) + current.value;
return result;
}, {});
// then recreate the objects with proper id and value properties
var result = [];
for (var key in temp) {
result.push({
id: parseInt(key, 10),
value: temp[key]
});
}
console.log(result);
Output
[ { id: 1, value: 15 },
{ id: 2, value: 12 },
{ id: 4, value: 3 } ]
The quickest approach loops over the array only once using Array.prototype.filter():
var tmp = {},
result = arr.filter(function (el) {
if (tmp.hasOwnProperty(el.id)) {
tmp[el.id].visit += el.visit;
return false;
}
else {
tmp[el.id] = el;
return true;
}
});
It also reuses the objects, though this renders the original array to contain inaccurate values. If this is a problem, you can modify the example to copy each object property to a new object.