delete property with sequential index in object - javascript

i have an object like below:
item = {
0: 'A',
1: 'B',
2: 'C',
3: 'D'
}
For e.g., if i would like to delete '1' from the item object and after it was deleted, '2' and '3' should auto minus 1 and become object below:
item = {
0: 'A',
1: 'C',
2: 'D'
}
Is it possible to achieve this with object beside using array?

Omit the key you don't want, convert to array using Object.values(), and then convert back to object by spreading to an empty object:
const item = {
0: 'A',
1: 'B',
2: 'C',
3: 'D'
}
const result = { ...Object.values(_.omit(item, 1)) }
console.log(result)
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.11/lodash.min.js"></script>
Or you can create a function that uses rest params:
const fn = (key, { [key]: _, ...rest }) => ({ ...Object.values(rest) })
const item = {
0: 'A',
1: 'B',
2: 'C',
3: 'D'
}
const result = fn(1, item)
console.log(result)

Use a delete statement
delete item["1"];

You can use an array for removing and for re-indexing purpose.
let item = {
0: 'A',
1: 'B',
2: 'C',
3: 'D'
};
// get values as an array
let arr = Object.values(item);
// remove element at index 1
arr.splice(1, 1);
// extract array to an object
item = {
...arr
};
console.log(item);

Here another solution in case you don't want to rely in third party plugins. Lodash is quite a heavy library as well.
var deleteObj = ({data, index}) => {
var objSize = Object.keys(data).length
if (index > objSize -1) return data
var count = index;
delete data[count];
count = count+1;
while (count < objSize){
data[count-1] = data[count];
count = count+1;
}
delete data[count-1];
return data;
}
deleteObj({data: {0: "A", 1: "B", 2: "C", 3: "D", 4: "E", 5: "F"}, index: 0});

Or else you can use lodash's filter directly on object (actually you can) to remove unnecessery items and then produce an array in one step, and then just use object spread operator to build back the resultant object.
Example:
let o = {"0":"A","1":"B","2":"C","3":"D"},
res = {..._.filter(o, (v, k) => k!=1)};
console.log(res);
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.11/lodash.min.js"></script>

Related

How does one compare every object-entry of an array-item to entries of another object while keeping/remembering each comparison result?

I have an array of 2 objects [ { bg: 'a', o: 'c' }, {'hg': 'a2', 'oo': 'c3' } ] coming from a json file. And I want to compare each object in the array to another object that looks like this { fm: 'a', fh: 'b', o: 'a', fe: 'b', ft: 'a', fb: 'c', bg: 'f' } to determine if this object has both sets of key/value pairs in either of the objects in the json array. How can I compare these objects?
The following approach utilizes
Object.entries in order to provide/access each of an object's key-value pair in its array/tuple form of [key, value].
Array.prototype.map in order to write for each array-item the boolean result of comparing every of its entries (key-value pairs) against an additionally provided object.
Array.prototype.every in order to retrieve the boolean value of comparing every of an array-item's entries (key-value pairs) against an additionally provided object.
const sampleArr = [ { bg: 'a', o: 'c' }, {'hg': 'a2', 'oo': 'c3' } ];
const sampleObj = { fm: 'a', fh: 'b', o: 'a', fe: 'b', ft: 'a', fb: 'c', bg: 'f' };
console.log("### How `Object.entries` works ###");
console.log({
sampleArr
});
console.log(
"sampleArr[0] => Object.entries(sampleArr[0]) ...",
sampleArr[0], " => ", Object.entries(sampleArr[0])
);
console.log(
"sampleArr[1] => Object.entries(sampleArr[1]) ...",
sampleArr[1], " => ", Object.entries(sampleArr[1])
);
console.log("### Comparison 1 with what was provided by the OP ###");
console.log(
sampleArr
// create a new array which for each ...
.map(item => {
// ... `sampleArr` item retrieves/maps whether ...
return Object
.entries(item)
// ... every entry of such an item exists
// as entry of another provided object.
.every(([key, value]) => sampleObj[key] === value)
})
);
sampleArr.push({ o: 'a', ft: 'a', fh: 'b' }); // will match ... maps to `true` value.
sampleArr.push({ o: 'a', ft: 'X', fh: 'b' }); // will not match ... maps to `false` value.
console.log("### Comparison 2 after pushing two more items into `sampleArr` ###");
console.log({
sampleArr
});
console.log(
sampleArr
// create a new array which for each ...
.map(item => {
// ... `sampleArr` item retrieves/maps whether ...
return Object
.entries(item)
// ... every entry of such an item exists
// as entry of another provided object.
.every(([key, value]) => sampleObj[key] === value)
})
);
.as-console-wrapper { min-height: 100%!important; top: 0; }

Create new object out of huge array of objects

I retrieve a huge array from the server (contains 2000+ objects). the structure of this array is like this:
const arr = [
{code: 'A', text:'blabla', codeParent:'-'},
{code: 'B', text:'blabla', codeParent:'-'},
{code: 'C', text:'blabla', codeParent:'-'},
{code: 'D', text:'blabla', codeParent:'-'},
{code: '01', text:'blabla', codeParent:'B'},
{code: '02', text:'blabla', codeParent:'C'},
{code: '03', text:'blabla', codeParent:'D'},
{code: '04', text:'blabla', codeParent:'A'},
{code: '05', text:'blabla', codeParent:'A'},
{code: '06', text:'blabla', codeParent:'B'},
...
]
The object that I want to make looks like this:
const obj = {
A: [array of all object with codeParent 'A'],
B: [array of all object with codeParent 'B'],
C: [array of all object with codeParent 'C'],
D: [array of all object with codeParent 'D']
}
Does anyone know the best way to get this result?
Assuming a couple things about your output that weren't entirely clear from your explanation, but appear to be the case from your sample output:
The output is collated by the codeParent property
You are skipping items that have codeParent: '-'
Then, you can just iterate through the big array and populate the output object as you go:
let result = {};
for (item of arr) {
let parent = item.codeParent;
if (parent !== '-') {
let destArray = obj[parent];
// if no array yet for this code, create one
if (!destArray) {
destArray = [];
obj[parent] = destArray;
}
// add the new item to the destination array
destArray.push(item);
}
}
console.log(result);
Some people will prefer to use .reduce() for this:
let result = arr.reduce((obj, item) => {
let parent = item.codeParent;
if (parent !== '-') {
let destArray = obj[parent];
// if no array yet for this code, create one
if (!destArray) {
destArray = [];
obj[parent] = destArray;
}
// add the new item to the destination array
destArray.push(item);
}
return obj;
}, {});
Note, each loop has slightly more code because I'm trying to only have to look up obj[item.codeParent] once for each iteration rather than multiple times and also trying to only look up the codeParent propery in item.codeParent once too. You could do it with less code like this and slightly less efficient:
let result = arr.reduce((obj, item) => {
if (item.codeParent !== '-') {
if (!obj[item.codeParent]) {
obj[item.codeParent] = [];
}
obj[item.codeParent].push(item);
}
return obj;
}, {});
Note that this looks up obj[item.codeParent] 2 or 3 times in every iteration whereas the previous two versions look it up 1 or 2 times.

Transform JS collection to an object with specific keys and grouped values

I would like to create this JS function with these arguments:
transform([{a:1, b:'1', c:true},{a:'1', b:2, c:3, d:false}, {a:1, c:'test'}], ['a','b','c']);
First argument is an array of objects
Second one is array of keys.
I would like to get this output object:
{a:[1, '1', 1], b:['1', 2],c:[true, 3, 'test']}
As you can see the second argument became the keys to the created object
and all values under these keys where grouped together.
And maybe an option to pass a unique argument to function and get this (duplicate values removed):
{a:[1, '1'], b:['1', 2], c:[true, 3, 'test']}
What is the fast and/or elegant way to do it?
Is there any lodash/underscore helper for it?
As an additional generalism. How can the input (the first argument) be a generic collection with nested levels (array or object of nested levels of arrays or objects) ?
Thanks.
You can use Array.prototype.reduce
let param1 = [{a:1,b:'1',c:true},{a:'1',b:2,c:3,d:false},{a:1,c:'test'}];
let param2 = ['a', 'b', 'c'];
function test(objArr, keys) {
let returnObject = {};
keys.forEach(key => returnObject[key] = []);
return objArr.reduce((ret, obj) => {
keys.forEach(key => {
if (obj[key] !== undefined)
ret[key].push(obj[key]);
});
return ret;
}, returnObject);
}
console.log(JSON.stringify(test(param1, param2)));
Outputs:
{"a":[1,"1",1],"b":["1",2],"c":[true,3,"test"]}
Try this:
function transform(data,keys){
let results = {};
//loop all you keys
keys.forEach(index => {
//loop your arrays
data.forEach(element => {
//if there is a match add the key to the results object
if(index in element) {
if(!(index in results)) results[index] = [];
//check if a value already exists for a given key.
if(!(element[index] in results[index])) results[index].push(element[index]);
}
});
});
return results;
}
console.log(transform([{a:1,b:'1',c:true},{a:'1',b:2,c:3,d:false},{a:1,c:'test'}], ['a','b','c']));
You can loop over the key array and pass this key to another function which will use forEach method. This getMatchedKeyValues using forEachwill return an array of elements whose key matches
var arr = [{
a: 1,
b: '1',
c: true
}, {
a: '1',
b: 2,
c: 3,
d: false
}, {
a: 1,
c: 'test'
}];
var keys = ['a', 'b', 'c']
function transform(keyArray) {
var newObj = {};
// looping over key array
keyArray.forEach(function(item) {
// adding key property and calling a function which will return
// an array of elements whose key is same
newObj[item] = getMatchedKeyValues(item)
})
return newObj;
}
function getMatchedKeyValues(keyName) {
var valArray = [];
arr.forEach(function(item) {
if (item[keyName]) {
valArray.push(item[keyName])
}
})
return valArray;
}
console.log(transform(keys))
I coded below , pls have a look this solution.
function test(arr, arr1) {
return arr.reduce((total, current) => {
arr1.forEach(curr => {
if (typeof total[curr] === "undefined") total[curr] = [];
if (current[curr]) total[curr].push(current[curr]);
});
return total;
}, {});
}
console.log(
test(
[
{ a: 1, b: "1", c: true },
{ a: "1", b: 2, c: 3, d: false },
{ a: 1, c: "test" }
],
["a", "b", "c"]
)
);

Another javascript array alphabetical sorting hardtime

I have an array that looks like this, how can I sort it alphabetically without loosing the key?
var items = [
{ 11: 'Edward' },
{ 12: 'Sharpe' },
{ 13: 'Alvin' }
];
You can sort the items array using Object.values.
const items = [
{ 11: 'Edward' },
{ 12: 'Sharpe' },
{ 13: 'Alvin' }
];
items.sort((a, b) => Object.values(a)[0] > Object.values(b)[0]);
console.log(items);
If the objects have only one key, then you can use Object.keys to retrieve that key an then sort:
var items = [
{ '11': 'Edward' },
{ '12': 'Sharpe' },
{ '13': 'Alvin' }
];
items.sort(function(a, b) {
var akey = Object.keys(a) [0], // get a's key
bkey = Object.keys(b) [0]; // get b's key
return a[akey].localeCompare(b[bkey]); // compare the values using those keys
});
console.log(items);
By using Object.keys, since they only have one value we don't know, we can use the length property minus one to get the actual key reference.
var items = [
{ 11: 'Edward' },
{ 12: 'Sharpe' },
{ 13: 'Alvin' }
];
items.sort(function(a, b){
var c = Object.keys(a);
var d = Object.keys(b);
return a[c[c.length-1]] > b[d[d.length-1]] ? 1: -1;
}
)
console.log(items);

Javascript reduce() on Object

There is nice Array method reduce() to get one value from the Array. Example:
[0,1,2,3,4].reduce(function(previousValue, currentValue, index, array){
return previousValue + currentValue;
});
What is the best way to achieve the same with objects? I'd like to do this:
{
a: {value:1},
b: {value:2},
c: {value:3}
}.reduce(function(previous, current, index, array){
return previous.value + current.value;
});
However, Object does not seem to have any reduce() method implemented.
One option would be to reduce the keys():
var o = {
a: {value:1},
b: {value:2},
c: {value:3}
};
Object.keys(o).reduce(function (previous, key) {
return previous + o[key].value;
}, 0);
With this, you'll want to specify an initial value or the 1st round will be 'a' + 2.
If you want the result as an Object ({ value: ... }), you'll have to initialize and return the object each time:
Object.keys(o).reduce(function (previous, key) {
previous.value += o[key].value;
return previous;
}, { value: 0 });
What you actually want in this case are the Object.values. Here is a concise ES6 implementation with that in mind:
const add = {
a: {value:1},
b: {value:2},
c: {value:3}
}
const total = Object.values(add).reduce((t, {value}) => t + value, 0)
console.log(total) // 6
or simply:
const add = {
a: 1,
b: 2,
c: 3
}
const total = Object.values(add).reduce((t, n) => t + n)
console.log(total) // 6
ES6 implementation: Object.entries()
const o = {
a: {value: 1},
b: {value: 2},
c: {value: 3}
};
const total = Object.entries(o).reduce(function (total, pair) {
const [key, value] = pair;
return total + value.value;
}, 0);
First of all, you don't quite get what's reduce's previous value is.
In you pseudo code you have return previous.value + current.value, therefore the previous value will be a number on the next call, not an object.
Second, reduce is an Array method, not an Object's one, and you can't rely on the order when you're iterating the properties of an object (see: https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Statements/for...in, this is applied to Object.keys too); so I'm not sure if applying reduce over an object makes sense.
However, if the order is not important, you can have:
Object.keys(obj).reduce(function(sum, key) {
return sum + obj[key].value;
}, 0);
Or you can just map the object's value:
Object.keys(obj).map(function(key) { return this[key].value }, obj).reduce(function (previous, current) {
return previous + current;
});
P.S. in ES6 with the fat arrow function's syntax (already in Firefox Nightly), you could shrink a bit:
Object.keys(obj).map(key => obj[key].value).reduce((previous, current) => previous + current);
1:
[{value:5}, {value:10}].reduce((previousValue, currentValue) => { return {value: previousValue.value + currentValue.value}})
>> Object {value: 15}
2:
[{value:5}, {value:10}].map(item => item.value).reduce((previousValue, currentValue) => {return previousValue + currentValue })
>> 15
3:
[{value:5}, {value:10}].reduce(function (previousValue, currentValue) {
return {value: previousValue.value + currentValue.value};
})
>> Object {value: 15}
An object can be turned into an array with: Object.entries(), Object.keys(), Object.values(), and then be reduced as array. But you can also reduce an object without creating the intermediate array.
I've created a little helper library odict for working with objects.
npm install --save odict
It has reduce function that works very much like Array.prototype.reduce():
export const reduce = (dict, reducer, accumulator) => {
for (const key in dict)
accumulator = reducer(accumulator, dict[key], key, dict);
return accumulator;
};
You could also assign it to:
Object.reduce = reduce;
as this method is very useful!
So the answer to your question would be:
const result = Object.reduce(
{
a: {value:1},
b: {value:2},
c: {value:3},
},
(accumulator, current) => (accumulator.value += current.value, accumulator), // reducer function must return accumulator
{value: 0} // initial accumulator value
);
Let me summarise the possibilities. The aim is always to make an array out of the object. There are various Javascript object functions for this. For each individual function, there are different ways of interpreting it. So it always depends on what our object looks like and what we want to do.
In the example above, it is an object with three objects.
const obj = {
a: {value: 1},
b: {value: 2},
c: {value:3}
};
With Object.keys
Object.keys only gives us the keys of the object.
const arr = Object.keys(obj);
// output arr:
[a, b, c]
const result = arr.reduce((total, key) => {
return sum + obj[key].value;
}, 0);
// output result
// 6
With Object.value
Object.value() returns the every single value in an array.
const arr = Object.value(obj);
// output arr
[
{value: 1},
{value: 2},
{value: 3},
]
const result = arr.reduce((total, singleValue) => {
return total + singleValue.value;
}, 0);
// output result
// 6
// Or the short variant
const resultShort = Object.values(obj).reduce((t, n) => t + n.value, 0)
// output resultShort
// 6
With Object.entries
Object.entries splits each individual object value into an array.
const arr = Object.entries(obj)
// output arr
[
["a", {visitors: 1}],
["b", {visitors: 2}],
["c", {visitors: 4}]
]
const result = arr.reduce((total, singleArr) => {
return total + singleArr[1].value;
}, 0);
// output result
// 6
Whether you do it with reduce or with the array function map() depends on you and what you want to do.
Extend Object.prototype.
Object.prototype.reduce = function( reduceCallback, initialValue ) {
var obj = this, keys = Object.keys( obj );
return keys.reduce( function( prevVal, item, idx, arr ) {
return reduceCallback( prevVal, item, obj[item], obj );
}, initialValue );
};
Sample of using.
var dataset = {
key1 : 'value1',
key2 : 'value2',
key3 : 'value3'
};
function reduceFn( prevVal, key, val, obj ) {
return prevVal + key + ' : ' + val + '; ';
}
console.log( dataset.reduce( reduceFn, 'initialValue' ) );
'Output' == 'initialValue; key1 : value1; key2 : value2; key3 : value3; '.
n'Joy it, guys!! ;-)
You can use a generator expression (supported in all browsers for years now, and in Node) to get the key-value pairs in a list you can reduce on:
>>> a = {"b": 3}
Object { b=3}
>>> [[i, a[i]] for (i in a) if (a.hasOwnProperty(i))]
[["b", 3]]
If you can use an array, do use an array, the length and order of an array are half its worth.
function reducer(obj, fun, temp){
if(typeof fun=== 'function'){
if(temp== undefined) temp= '';
for(var p in obj){
if(obj.hasOwnProperty(p)){
temp= fun(obj[p], temp, p, obj);
}
}
}
return temp;
}
var O={a:{value:1},b:{value:2},c:{value:3}}
reducer(O, function(a, b){return a.value+b;},0);
/* returned value: (Number)
6
*/
This is not very difficult to implement yourself:
function reduceObj(obj, callback, initial) {
"use strict";
var key, lastvalue, firstIteration = true;
if (typeof callback !== 'function') {
throw new TypeError(callback + 'is not a function');
}
if (arguments.length > 2) {
// initial value set
firstIteration = false;
lastvalue = initial;
}
for (key in obj) {
if (!obj.hasOwnProperty(key)) continue;
if (firstIteration)
firstIteration = false;
lastvalue = obj[key];
continue;
}
lastvalue = callback(lastvalue, obj[key], key, obj);
}
if (firstIteration) {
throw new TypeError('Reduce of empty object with no initial value');
}
return lastvalue;
}
In action:
var o = {a: {value:1}, b: {value:2}, c: {value:3}};
reduceObj(o, function(prev, curr) { prev.value += cur.value; return prev;}, {value:0});
reduceObj(o, function(prev, curr) { return {value: prev.value + curr.value};});
// both == { value: 6 };
reduceObj(o, function(prev, curr) { return prev + curr.value; }, 0);
// == 6
You can also add it to the Object prototype:
if (typeof Object.prototype.reduce !== 'function') {
Object.prototype.reduce = function(callback, initial) {
"use strict";
var args = Array.prototype.slice(arguments);
args.unshift(this);
return reduceObj.apply(null, args);
}
}
Try this one. It will sort numbers from other variables.
const obj = {
a: 1,
b: 2,
c: 3
};
const result = Object.keys(obj)
.reduce((acc, rec) => typeof obj[rec] === "number" ? acc.concat([obj[rec]]) : acc, [])
.reduce((acc, rec) => acc + rec)
If handled as an array is much easier
Return the total amount of fruits:
let fruits = [{ name: 'banana', id: 0, quantity: 9 }, { name: 'strawberry', id: 1, quantity: 1 }, { name: 'kiwi', id: 2, quantity: 2 }, { name: 'apple', id: 3, quantity: 4 }]
let total = fruits.reduce((sum, f) => sum + f.quantity, 0);
Since it hasnt really been confirmed in an answer yet, Underscore's reduce also works for this.
_.reduce({
a: {value:1},
b: {value:2},
c: {value:3}
}, function(prev, current){
//prev is either first object or total value
var total = prev.value || prev
return total + current.value
})
Note, _.reduce will return the only value (object or otherwise) if the list object only has one item, without calling iterator function.
_.reduce({
a: {value:1}
}, function(prev, current){
//not called
})
//returns {value: 1} instead of 1
Try out this one liner arrow function
Object.values(o).map(a => a.value, o).reduce((ac, key, index, arr) => ac+=key)

Categories

Resources