populate array based on value banding - javascript

I need to create an array of data based on the "age" of a person. This banding is not linear, but grouped something like
1,2,3,4,5,6,7,8,9,10,11-15,16-20,21-30,31-50,51+
so for any set of data, I need to run through this and put the person into the appropriate age "bucket"
At the end of the loop, I want to see how many people are in each banding.
Now, I have done this by using very crude techniques (aka if this .. then .. else if .. ) ;), but was wondering if I could learn new techniques and if there was any library or function that could take a range and fill the bucket accordingly

That's what I would do:
let buckets = '1,2,3,4,5,6,7,8,9,10,11-15,16-20,21-30,31-50,51+'.split(','),
bucketByAge = {}; // our bucket-age connector where we search later on
// prepare the index
buckets.forEach(function(bucket, index) {
// get the range (+ will be replaced with 1000; for the age it is infinity)
// and transform them to numbers
let range = bucket.replace('+', '-1000').split('-').map(Number);
// if it was not a range, simulate one
range[1] = range[1] || range[0];
// go through the range and fill our connector
while (range[0] <= range[1]--) {
bucketByAge[range[1]] = index;
}
});
// search
function getBucket(age) {
return { age: age, bucketRange: buckets[bucketByAge[age]], bucketIndex: bucketByAge[age] };
}
console.log(getBucket(1));
console.log(getBucket(12));
console.log(getBucket(61));
What's good here: you build the index once and later just take the result. Very performant.

A VERY rough o(n^2) implementation
const buckets = [
{
lowerLim: 1,
upperLim: 1,
persons: 0
},
{
lowerLim: 2,
upperLim: 2,
persons: 0
},
{
lowerLim: 3,
upperLim: 5,
persons: 0
},
{
lowerLim: 6,
upperLim: 10,
persons: 0
},
{
lowerLim: 11,
persons: 0
}
];
const persons = [{name: 'john', age: 1},{name: 'john', age: 2}, {name: 'john', age: 6}, {name: 'john', age: 20}, {name: 'john', age: 40}, {name: 'john', age: 7}, {name: 'john', age: 1}];
persons.forEach(person => {
buckets.forEach(bucket => {
const age = person.age;
const bucketLowerLimit = bucket.lowerLim;
const bucketUpperLimit = bucket.upperLim || Number.MAX_SAFE_INTEGER;
if(age >= bucketLowerLimit && age <= bucketUpperLimit) {
bucket.persons++;
}
})
});
buckets.forEach(bucket => {
console.log(bucket.persons);
});

You could use a reference for all values inbetween and a separate last value.
var slots = '1,2,3,4,5,6,7,8,9,10,11-15,16-20,21-30,31-50,51+'.split(','),
last = slots.pop(),
reference = Object.create(null),
histogram = Object.create(null),
i, value;
slots.forEach(function (a) {
var temp = a.split('-'),
left = temp[0],
right = temp[1] || temp[0];
histogram[a] = 0;
reference[right] = a;
while (left < right) {
reference[left] = a;
left++;
}
});
histogram[last] = 0;
for (i = 0; i < 1000000; i++) {
value = Math.floor(Math.random() * 100);
histogram[reference[value] || last]++;
}
console.log(histogram);
console.log(reference);
.as-console-wrapper { max-height: 100% !important; top: 0; }

Related

Divide object array elements into groups of n each javascript

I have an Object as below:
const boxOfFruits = {
apples: [
{
name: "Kashmiri",
},
{
name: "Washington",
},
{
name: "Himalayan",
},
{
name: "Fuji",
}
],
oranges: [
{
name: "Nagpur",
},
{
name: "Clementine",
},
],
mangoes: [
{
name: "Totapuri",
},
{
name: "Alphonso",
},
{
name: "Langda",
},
],
}
I want to divide these fruits into boxes; maximum of n each, let's say where n is 3 and apples, oranges and mangoes are equally distributed.
So the output in this case would be:
box_1 = [{name: "Kashmiri"}, {name: "Nagpur"},{name: "Totapuri"}];
box_2 = [{name: "Washington"}, {name: "Clementine"},{name: "Alphonso"}];
box_3 = [{name: "Himalayan"},{name: "Langda"}, {name: "Fuji"}];
The type of fruits(apple,oranges,etc)/keys in object can increase/decrease and n is also variable. In case total fruits are less than n, then it would be just 1 box of fruits.
What I have tried so far:
Using Lodash, I am calculating the minimum and the maximum fruits in a single type:
const minFruitType = _.min(Object.values(basket).map((eachBasket: any) => eachBasket.length));
Total teams will the sum of the fruits / n
Will distribute the minimum fruits (l) in the first l boxes and fill the rest with the remaining fruits at every iteration while at the start of every iteration will calculate the minimum type of fruits again.
You can use Object.values(), array#reduce and array#forEach to transform your object.
const boxOfFruits = { apples: [ { name: "Kashmiri", }, { name: "Washington", }, { name: "Himalayan", }, ], oranges: [ { name: "Nagpur", }, { name: "Clementine", }, ], mangoes: [ { name: "Totapuri", }, { name: "Alphonso", }, { name: "Langda", }, ], },
result = Object.values(boxOfFruits).reduce((r, arr) => {
arr.forEach((o,i) => {
const key = `box_${i+1}`;
r[key] ??= r[key] || [];
r[key].push(o)
});
return r;
},{});
console.log(result);
The easiest way would be to use lodash.js's zip() function:
const boxes = _.zip( Object.values(boxOfFruits) );
Note that _.zip() will give you undefined values when the source arrays are different lengths, so you'll need/want to filter those out:
const boxes == _.zip( Object.values(boxOfFruits) )
.map(
box => box.filter(
x => x !== undefined
)
);
But that will not distribute the fruits evenly. For that, it shouldn't get much for difficult than this:
function distribute(boxOfFruits, n) {
const boxes = [];
const fruits = Object.keys(boxOfFruits);
for ( const fruit of fruits ) {
let i = 0;
const items = boxOfFruits[fruit];
for (const item of items) {
boxes[i] = !boxes[i] ?? [];
boxes[i] = boxes[i].push(item);
++i;
i = i < n ? i : 0 ;
}
}
return boxes;
}
A modified version of #Nicholas Carey's answer worked for me:
function distribute(boxOfFruits, n) {
let boxes = [];
let totalFruits = Object.values(boxOfFruits)
.reduce((content, current) => content + current.length, 0);
let maxBoxes = Math.ceil(totalFruits / 4);
Object.values(boxOfFruits).forEach((fruits) => {
let i = 0;
fruits.forEach((fruit) => {
boxes[i] ??= boxes[i] || [];
boxes[i].push(fruit);
++i;
i = i < (n+1) ? i : 0;
});
});
// Extra boxes created, redistribute them to
// starting boxes
let newBoxes = teams.slice(0, maxBoxes);
let pendingBoxes = teams.slice(maxBoxes);
let pendingFruits = pendingBoxes.flat();
let distributedBoxes = newBoxes.map((eachBox) => {
let required = n - eachBox.length;
if (required > 0) {
eachBox.push(...pendingFruits.splice(0, required));
}
return eachBox;
});
return distributedBoxes;
}
Code is pretty much the same as Nicholas's accept the below changes:
Directly fetched the values and iterated over those
empty array creation was failing, this way works
and checking on the max box size with n+1 instead of n

Javascript find the closest number in an array of objects and retrieve the object's key value

I have an array of objects(with keys: name, quoteNumber)and I would like to find the closest quoteNumber that is smaller than a given number then retrieve that object's name, I have consider using a for loop to remove the larger values, and get the max value from the remaining ones ,yet it might not be the best option given how large the dataset would be. Is this any other algorithm that is more efficient? Thanks!
const givenNum = 45
var array = [
{ name: "Sally",
quoteNumber: 35},
{ name: "Jane",
quoteNumber: 20},
{ name: "Edwin",
quoteNumber: 55},
{ name: "Carrie",
quoteNumber: 47}];
//'result:' Sally
If it's unsorted, about the most efficient you can be is a single pass.
function getHighestQuote(quotes, limit) {
let winner = null;
let winningQuote = null;
for (let {name, quoteNumber} of quotes) {
if (quoteNumber > limit)
continue;
if (winningQuote === null || winningQuote < quoteNumber) {
winner = name;
winningQuote = quoteNumber;
}
}
return winner;
}
It's not quite as snazzy as a functional approach, but it's a single linear-time pass that only needs to allocate a few stack variables.
If you have a large dataset, you want to avoid doing anything which either loops over the array more than once, or even attempts to sort it before looking. A simple aggregate operation will do this fine. Use reduce
const givenNum = 45
var array = [
{ name: "Sally",
quoteNumber: 35},
{ name: "Jane",
quoteNumber: 20},
{ name: "Edwin",
quoteNumber: 55},
{ name: "Carrie",
quoteNumber: 47}];
const result = array.reduce ( (acc,item) => {
const diff = givenNum - item.quoteNumber;
if(item.quoteNumber < givenNum && diff < acc.diff)
acc = {diff, item}
return acc;
},{ diff: Number.MAX_SAFE_INTEGER, item: null });
console.log(result.item);
Note also that if speed is really important avoid this solution too - it has extra method calls you won't have with with the simpler loop solution. That will always be the fastest option.
I've made a simple one-liner that kicks out all elements with a larger quote-number, sorts the other elements and finally get's the first element(-> the closest one):
const closest_smaller = array.filter(a => a.quoteNumber <= givenNum).sort((a,b) => b.quoteNumber-a.quoteNumber)[0]
If the givenNum is smaller than every quoteNumber, this returns undefined.
if you want to have a fallback use:
const closest_smaller = array.filter(a => a.quoteNumber <= givenNum).sort((a,b) => b.quoteNumber-a.quoteNumber)[0] ?? 0
You also can use find instead of filter, i don't exactly know which one is faster:
const closest_smaller = array.sort((a,b) => b.quoteNumber-a.quoteNumber).find(a => a.quoteNumber <= givenNum) ?? 0
This is based on #Jeremy Roman's and #Jamiec's answers. I think this is a good bit faster unless I've done something stupid: https://jsbench.me/g0kmha8buo/1
const array = [
{ name: "Sally",
quoteNumber: 35},
{ name: "Jane",
quoteNumber: 20},
{ name: "Velma",
quoteNumber: 31},
{ name: "Edwin",
quoteNumber: 55},
{ name: "Neva",
quoteNumber: 30},
{ name: "Carrie",
quoteNumber: 47},
{ name: "Arnold",
quoteNumber: 29},
];
function closest_quote_less_than_or_equal_to(quotes, limit) {
let winner = null;
let winningQuote = 0;
const limit_plus_one = limit + 1;
for(let i = 0; i < quotes.length; i++) {
const quoteNumber = quotes[i].quoteNumber;
if(((quoteNumber < limit_plus_one) * quoteNumber) > winningQuote) {
winningQuote = quoteNumber;
winner = quotes[i].name;
}
}
return winner;
}
console.log(closest_quote_less_than_or_equal_to(array, 45));
console.log(closest_quote_less_than_or_equal_to(array, 30));
console.log(closest_quote_less_than_or_equal_to(array, 10));

Find object in array with closest value

I need to get an object in an array by the closest value. Let me explain it by an example:
const data = [
{ age: 52 },
{ age: 53 },
{ age: 54 },
{ age: 60, some: 'data' },
{ age: 66, something: 'else' },
{ age: 72 },
{ age: 78 },
{ age: 84 }
]
I do get the object by using data.find((d)=> d.age === 60). But I do not get an result if the age is 61.
In this case I would like to get the same object.
For 64 the next object ({ age: 66, something: 'else' }) should be returned.
As you can see the age value is not linear.
You can find the difference between all the numbers and whichever one is closest to zero will be your result, to achieve this I have used .reduce() with Math.abs()
const data = [ { age: 52 }, { age: 53 }, { age: 54 }, { age: 60 }, { age: 66 }, { age: 72 }, { age: 78 }, { age: 84 } ];
const getAge = (data, target) =>
data.reduce((acc, obj) =>
Math.abs(target - obj.age) < Math.abs(target - acc.age) ? obj : acc
);
console.log(getAge(data, 61)); // {age: 60}
console.log(getAge(data, 50)); // {age: 52}
console.log(getAge(data, -1)); // {age: 52}
console.log(getAge(data, 90)); // {age: 84}
This will also work for more generalized objects that have additional properties other than just age.
Here is a fully abstract approach to your problem:
// Saves up vertical space
const data = JSON.parse(`[{"age":52},{"age":53},{"age":54},{"age":60},{"age":66},{"age":72},{"age":78},{"age":84}]`);
function getClosestValue(list, getDifference) {
var smallestDiff = Infinity;
return list.reduce(function(closestValue, currentValue, index) {
var newDifference = Math.abs(getDifference(currentValue));
if (!index) return smallestDiff = newDifference, currentValue;
return smallestDiff = Math.min(smallestDiff, newDifference), newDifference === smallestDiff ? currentValue : closestValue;
});
}
function getClosestAge(list, age) {
return getClosestValue(list, function(listValue) {
return listValue.age - age;
});
}
console.log(getClosestAge(data, 65));
If it's always sorted you can instead use some:
// Saves up vertical space
const data = JSON.parse(`[{"age":52},{"age":53},{"age":54},{"age":60},{"age":66},{"age":72},{"age":78},{"age":84}]`);
function getClosestValue(list, getDifference) {
var smallestDiff = Infinity;
var closestValue;
list.some(function(currentValue, index) {
var newDifference = Math.abs(getDifference(currentValue));
if (!index) return smallestDiff = newDifference, closestValue = currentValue, false;
if (smallestDiff > newDifference) return smallestDiff = newDifference, closestValue = currentValue, false;
else if (smallestDiff !== newDifference) return true;
});
return closestValue;
}
function getClosestAge(list, age) {
return getClosestValue(list, function(listValue) {
return listValue.age - age;
});
}
console.log(getClosestAge(data, 65));
Assume, that your list ist not Sorted, and you do not want to sort your list. So you can pick the first object, iterate through your list and check if you get an item, which fits your requiremnt more than your currently picked item. If so, you just replace your item with the better one.
e.g.
var data = [/*...*/];
var find_age = 64; // input
var best_item = data[0]; // pick any item as best item
for (var i = 1; i < data.length; i++) {
// does date[i] match the requirement better than best_item?
if (Math.abs (best_item.age - find_age) > Math.abs (data[i].age - find_age)) {
// it does ... so update best_item
best_item = data[i];
}
}
// best_item stores the item which matches your requirement most.
If your dataset is sorted, you can optimize your runtime.
You can just sort the array by difference to lookup age:
const lookupAge = 61
const data = [
{ age: 52 },
{ age: 53 },
{ age: 54 },
{ age: 60 },
{ age: 66 },
{ age: 72 },
{ age: 78 },
{ age: 84 }
]
const result = data
.map(d => d.age)
.sort((a, b) => Math.abs(a - lookupAge) - Math.abs(b - lookupAge))
console.log('result', result)
const data = [
{ age: 52 },
{ age: 53 },
{ age: 54 },
{ age: 60 },
{ age: 66 },
{ age: 72 },
{ age: 78 },
{ age: 84 }
];
const find = 64;
const result = data.map(({ age }) => age).reduce((best, el, index) => {
if (Math.abs(find - el) < Math.abs(find - best)) {
return el;
}
return best;
}, data[0].age)
console.log(result)
With sorted data, you could take the one with the greatest value as start value an iterate from the beginning and stop the iteration if the delta grows.
var data = [{ age: 52 }, { age: 53 }, { age: 54 }, { age: 60 }, { age: 66 }, { age: 72 }, { age: 78 }, { age: 84 }],
result = data[data.length - 1],
age = 61;
data.some((o) => {
if (Math.abs(age - o.age) >= Math.abs(age - result.age)) return true;
result = o;
});
console.log(result);
I made a lil' snippet code to show you the way I would do this. This creates to use a findClosest method on any array of object, that expects an attribute name and a value. The function will then return the element of the array that has the closest value to the given attribute. It could be improved but this works pretty well.
document.addEventListener("DOMContentLoaded", function() {
const listElem = document.getElementById('list');
const closestElem = document.getElementById('closest');
data.forEach(elem => {
const listElemEntry = document.createElement('li');
listElemEntry.innerHTML = elem.age;
listElem.appendChild(listElemEntry);
});
const closest = data.findClosest('age', 80);
closestElem.innerHTML = closest;
});
const data = [
{ age: 52 },
{ age: 53 },
{ age: 54 },
{ age: 60 },
{ age: 66 },
{ age: 72 },
{ age: 78 },
{ age: 84 }
];
Array.prototype.findClosest = function(attr, value) {
const closestElem = { diff: Infinity, index: -1 };
this.forEach((elem, index) => {
const diff = Math.abs(elem[attr] - value);
if (diff < closestElem.diff) {
closestElem.diff = diff;
closestElem.index = index;
}
});
return this[closestElem.index][attr];
}
<h2>Elements list</h2>
<ul id="list"></ul>
<h2>Closest element</h2>
<pre id="closest"></pre>
You can find closest item of array with minimum value of differences like below;
function getClosest(data, x) {
if (data.length == 0) {
return null;
}
var index = 0;
var difference = Number.MAX_SAFE_INTEGER;
for(var i = 0; i<data.length;i++) {
if (i < data.length) {
var differ = Math.abs(data[i].age - x);
if(differ < difference) {
difference = differ;
index = i;
}
}
}
return data[index];
}
Usage:
getClosest(data, 64)
You can find the minimum difference by subtracting the given number from every element and take the absolute value and then do both higher lookup and lower lookup
it will also consider when there are 2 different closest values
const data = [
{ age: 52 },
{ age: 53 },
{ age: 55 },
{ age: 60 },
{ age: 66 },
{ age: 72 },
{ age: 78 },
{ age: 84 }
]
function minimum(given){
//let given=54
//find the mimimun different
let closest_diff=Math.min(...data.map(a=>Math.abs(a.age-given)))
//for lower closest number
let x1=data.find(a=>a.age===given-closest_diff);
//for highter closest number
let x2=data.find(a=>a.age===given+closest_diff);
//filter the number which are in array above
console.log(...new Set([x1,x2].filter(x=>x)));
}
minimum(52); //52
minimum(54); //53 and 55
minimum(63); //60 and 66
minimum(75); //72 and 78
minimum(77); //78
Suppose array isn't sorted. Following function returns result. If it find value that is equal to search value, it stops searching, so it is a small gain in performance.
function minDiff(data, val) {
let res = null;
let n = data.length;
let diffGet = (val1, val2) => Math.abs(val1 - val2);
if (n>0) {
res = data[0];
let diff = diffGet(res.age, val);
let i = 1;
while ( diff>0 && i<n ) {
if (diffGet(data[i].age, val) < diff) {
res = data[i];
diff = diffGet(res.age, val);
}
i++;
}
}
return res;
}
This is a functional approach to your problem with currying:
const data = [
{ age: 52 },
{ age: 53 },
{ age: 54 },
{
age: 60,
some: "data"
},
{
age: 66,
something: "else"
},
{ age: 72 },
{ age: 78 },
{ age: 84 }
];
const indexOfSmallest = (array) => {
if (array.length === 0) {
throw new Error("Empty array, expects at least one element");
}
return array.reduce((lowest, next, index) => {
if (next < array[lowest]) {
return index;
}
return lowest;
}, 0);
};
const getClosestIndex = (numbers, referenceNumber) => {
const diff = numbers.map(n => Math.abs(referenceNumber - n));
return indexOfSmallest(diff);
};
const createGetClosestIndex = (numbers) => (number) => getClosestIndex(numbers, number);
const createGetClosestPerson = (people) => {
return (targetAge) => {
const numbers = people.map(d => d.age);
const index = createGetClosestIndex(numbers)(targetAge);
return people[index];
};
};
const getClosest = createGetClosestPerson(data);
console.log(getClosest(1), getClosest(64));
A general purpose version of #nick-parsons excellent answer...
/**
* Find the closest number in an array.
*
* #param Number needle The number we're looking for.
* #param Array<Number|Object> haystack An array to search.
* #param String [key] We're searching an array of objects.
* Use this key to find the number in each object.
* #return Number|Object
*/
function closest (needle, haystack, key=null) {
if (key==null) {
return haystack.reduce((a, b) => Math.abs(needle - b) < Math.abs(needle - a) ? b : a);
}
return haystack.reduce((a, b) => {
if (b[key] == null) return a;
if (a[key] == null) return b;
return Math.abs(needle - b[key]) < Math.abs(needle - a[key]) ? b : a;
});
}
let arr = [ {speed: 0.1}, {speed: 0.4}, {speed: 1} ]
console.log( closest(0.5, arr, "speed").speed )
// output: 0.4
arr = [ 0.1, 0.4, 1 ]
console.log( closest(0.9, arr) )
// output: 1

Loop through an array of objects and sort them

I have an array containing some objects and I am trying to loop through it where I have data stored in the following order:
firstName: Alice
lastName: Wonderland
age:12
I am trying to loop, then to sort it in descending order where age: value should be in first position then > lastName: Wonderland comes and lastly firstName.
Here is my code until this moment
var data = {
example1: [{
firstName: 'Alice',
lastName: 'Wonderland',
age: 12
}],
example2: [{
firstName: 'Thomas',
lastName: 'Mathison',
age: 14
}],
example3: [{
firstName: 'David',
lastName: 'Jacobsen',
age: 18
}]
};
for (var key in data) {
var arr = data[key];
for (var i = 0; i < arr.length; i++) {
var obj = arr[i];
for (var prop in obj) {
if (obj.hasOwnProperty(prop)) {
console.log(prop + ': ' + obj[prop]);
}
}
}
}
I want to achieve the reverse order (descending) when I output the result in the console.log();:
age: 12,
lastName: 'Wonderland',
firstName: 'Alice'
age:14,
lastName: 'Mathison',
firstName: 'Thomas'
age:18,
lastName: 'Jacobsen',
firstName: 'David'
I am not sure about the sort function behavior. How should it work during the loop?
Any suggestions?
var data = {
example1: [{
firstName: 'Alice',
lastName: 'Wonderland',
age: 12
}],
example2: [{
firstName: 'Thomas',
lastName: 'Mathison',
age: 14
}],
example3: [{
firstName: 'David',
lastName: 'Jacobsen',
age: 18
}]
};
var objectArray=[];
for (var key in data) {
var arr = data[key];
for (var i = 0; i < arr.length; i++) {
var obj = arr[i];
objectArray.push(obj);
}
}
objectArray.sort(function(element1,element2){
return element2.age - element1.age
}); //now iterate over the array it is sorted in descending order
Sorting arrays of non-primitive data types (custom objects and data structures like in your case) require two steps. It's quite straightforward so follow along.
First you need to create a function capable of comparing two objects of your custom data structure according to your desired criteria.
Second, you provide this decision function to a sort function along with your array and it will use it to sort the array for you. Lets do it for your case:
First the compare function, a and b are objects from your custom structure. returning 1 means object a is "bigger", returning -1 means b is "bigger", returning 0 means that, according to your criteria, both are equal in "size". The order of the if statements bellow is naturally important and reflects the priorities you described:
age takes priority over names and last-name over first-name.
function compare_people(a, b) {
if (a.age < b.age) {
return -1;
}
if (a.age > b.age) {
return 1;
}
if (a.lastName < b.lastName) {
return -1;
}
if (a.lastName > b.lastName) {
return 1;
}
if (a.firstName< b.firstName) {
return -1;
}
if (a.firstName> b.firstName) {
return 1;
}
return 0;
}
Now all you have to do is provide your criteria and array to javascript's sort function. In your case objects are stored inside the data array, so you do:
data.sort(compare_people);
Done, array sorted!
Here you can study the concept more in depth https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/sort
Good luck.
Apparently the question is not clear enough, people keep giving you sorting algorithms which I understand it is not what you are looking for, you want to change the internal order of the properties (which makes no sense, they have no 'order' they are part of a map, in any case, here is what I would do:
var data = {
example1: [{
firstName: 'Alice',
lastName: 'Wonderland',
age: 12
}],
example2: [{
firstName: 'Thomas',
lastName: 'Mathison',
age: 14
}],
example3: [{
firstName: 'David',
lastName: 'Jacobsen',
age: 18
}]
};
for (var key in data) {
var arr = data[key];
var newArr = [];
for (var i = 0; i < arr.length; i++) {
var obj = arr[i];
newArr.push({
age: obj.age,
firstName: obj.firstName,
lastName: obj.lastName
})
}
data[key] = newArr;
}
But again, what you are trying to do makes no sense, or at least according to the description.
Use [].unshift() method
var result = [];
for (var key in data) {
var arr = data[key];
for (var i = 0; i < arr.length; i++) {
var obj = arr[i];
for (var prop in obj) {
if (obj.hasOwnProperty(prop)) {
result.unshift(prop + ': ' + obj[prop])
}
}
}
}
console.log(result)
here is demo https://plnkr.co/edit/N4Zt28zh0A3MpwoOrzmZ?p=preview

Object Splicing within Array not giving correct result

In my application i want to splice objects from an array upon matching, I am using lodash function for splicing like as shown below, unfortunately the json is not splicing correctly,
Working Demo
Can anyone give me some suggestion for this issue
var arr = [{
name: 'Jack',
id: 125
}, {
name: 'Jack',
id: 125
}];
var result = _.without(arr, _.findWhere(arr, {name: 'Jack'}));
console.log(JSON.stringify(result));
Expected result
[]
Actual Result
[{"name":"Jack","id":125}]
Update 1
Even using normal JavaScript way also giving the same output
for(var i = 0; i < arr.length; i++) {
var obj = arr[i];
if(obj.name === 'Jack') {
arr.splice(i, 1);
}
}
#1
var arr = [{
name: 'Jack',
id: 125
}, {
name: 'Jack',
id: 125
}];
var result = _.rest(arr, function (el) {
return el.name === 'Jack';
});
console.log(JSON.stringify(result)); // "[]"
#2
var arr = [{
name: 'Jack',
id: 125
}, {
name: 'Jack',
id: 125
}, {
name: 'foo',
id: 124
}];
var result = _.rest(arr, function (e) {
return e.name === 'Jack';
});
console.log(JSON.stringify(result)); // "[{\"name\":\"foo\",\"id\":124}]"
// 3 also you can use _.filter if you do not want slice of array...
var result = _.filter(arr, function (e) {
return e.name !== 'Jack';
});
console.log(JSON.stringify(result)); // "[{\"name\":\"foo\",\"id\":124}]"
_.findWhere returns only the first matching element. So that you can use _.difference and _.filter or _.rest to do the task
_.difference(arr, _.filter(arr,function(d){ return d.name = 'Jack' }));
You can implement the same using pure javascript using the code below.
for(var i = 0; i < arr.length; i++) {
var obj = arr[i];
if(obj.name === 'Jack') {
arr.splice(i, 1);
i--; // Splicing of elements will cause shifting of indices in the array
}
}

Categories

Resources