Another javascript array alphabetical sorting hardtime - javascript

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);

Related

delete property with sequential index in object

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>

How to display nested key of object from left to right?

I have an object
var tree = {
17:{
1:{
3:{},
4:{}
},
2:{
5:{},
6:{}
}
}
};
How to display the keys in this order 17, 1, 2, 3,4, 5,6 ?
i have tried this function:
var arr = [] ;
var arrObject = [] ;
function printValues(obj) {
for (var key in obj) {
arr.push(key);
if (typeof obj[key] === "object") {
arrObject.push(obj[key]);
printValues(obj[key]);
}
}
}
printValues(tree);
the result is 17,1,3,42,5,6 .
and i need 17, 1, 2, 3,4, 5,6
The following uses a recursive function to extract all the nested keys associated with their depth in the object. It then sorts the results by depth.
Note that the approach may change the order of the keys at a given depth. To demonstrate this, I change the 3 in your example to 99. The returned results include "4", "99", not "99", "4". However, as pointed out in the comment by #deceze, the order of properties in an object is undefined anyway, so changing the order within a given object depth shouldn't (hopefully) be a problem. (If it is a problem then you need a different approach, e.g. using an array instead of an object.)
Note also that the code below returns an array of strings. This would be especially appropriate if some of your keys are explicitly strings, e.g. using letters. If you really want the results to be numerical, just add a + to the map command, i.e. ... .map(elmt => +elmt[1]).
const getKeysOrderedByDepth = obj => {
let arr = [], level = 0;
const getKeys = obj => {
level += 1;
for (let key in obj) {
arr.push([level, key]);
const val = obj[key];
getKeys(obj[key]);
}
level -= 1;
};
getKeys(obj);
return arr.sort((a, b) => a[0] - b[0]).map(elmt => elmt[1]);
};
let tree = {
17: {
1: {
99: {},
4: {}
},
2: {
5: {},
6: {}
}
}
};
console.log(getKeysOrderedByDepth(tree));
This is works for me(changed):
const tree = {
first:{
1:{
3:{
7: 7,
8: 8,
},
4:{
9: 9,
10: 10,
}
},
2:{
5:{
20: {
30: 30,
},
21: {
31: 31,
}
},
6:{
22: 22,
}
},
},
};
const keys = [];
/**
* Handle merged values
* #param values
*/
function handleData(values) {
let subValues = {};
for (let key in values) {
keys.push(key);
Object.assign(subValues, handle(values[key]));
}
// If have values, handle them
if (Object.keys(subValues).length) handleData(subValues);
}
/**
* Handle one value
* #param value
* #returns {{}}
*/
function handle(value) {
if (Object.keys(value).length) {
return Object.assign({}, value);
}
}
// Handle our data
handleData(tree);
console.log(keys); // ['first',1,2,3,4,5,6,7,8,9,10,20,21,22,30,31]

Array of objects, sum by key but the key is unkown

For instance the array:
var arr = [
{
Test 0: 142.0465973851827,
Test 1: 199,
timestamp: "2017-01-16T00:00:00.000Z"
},
{
Test 0: 142.0465973851827,
Test 1: 199,
timestamp: "2017-01-17T00:00:00.000Z"
}
]
Test 0 and Test 1 can be anything. and I try to return such result:
var arr = [
{
total: 341,
timestamp: '2017-01-16T00:00:00.000Z'
},
{
total: 341,
timestamp: '2017-01-17T00:00:00.000'
}
]
What would be the proper loop type to do it?
You can map over the array, then run reduce on the Object.keys of each object, excluding the timestamp property
var arr = [{
Test0: 142.0465973851827,
Test1: 199,
timestamp: "2017-01-16T00:00:00.000Z"
}, {
Test0: 142.0465973851827,
Test1: 199,
timestamp: "2017-01-17T00:00:00.000Z"
}]
var res = arr.map(v => ({
total: Object.keys(v).reduce((a, b) => b !== 'timestamp' ? a + v[b] : a, 0),
timestamp: v.timestamp
}));
console.log(res);
A combination of array.map, Object.keys, array.filter, and array.reduce can do this. Use array.map to run through the array, Object.keys to get the keys of each object and array.filter to only grab the keys starting with "Test", then accumulate results using array.reduce.
All of the above can easily be done using simple loops as well. The array methods can be done using a regular for loop, while Object.keys will need a for-in guarded with object.hasOwnProperty.
like this?
function number(v){ return +v || 0; }
arr.map(function(obj){
var timestamp = obj.timestamp;
var total = Object.keys(obj)
.reduce(function(sum, key){
return sum + number( obj[key] );
}, 0);
return { total, timestamp }
})
What about this?
var arr = [
{
Test0: 142.0465973851827,
Test1: 199,
timestamp: "2017-01-16T00:00:00.000Z"
},
{
Test0: 142.0465973851827,
Test1: 199,
timestamp: "2017-01-17T00:00:00.000Z"
}
];
var result = [];
var exclude = "timestamp";
arr.forEach(function(elements){
var sum = 0;
for(key in elements){
if(key !== exclude){
sum += elements[key];
}
}
var newElement = {total: sum.toFixed(2), timestamp: elements.timestamp}
result.push(newElement);
});
console.info(result);
arr=arr.map(el=>{return el.total=Object.keys(el).filter(key=>key.split("Test")[1]).reduce((total,key)=>total+el[key],0),el;});
it does exactly what joseph the dreamer described in the first part of his answer.

How to convert an Object {} to an Array [] of key-value pairs in JavaScript

I want to convert an object like this:
{"1":5,"2":7,"3":0,"4":0,"5":0,"6":0,"7":0,"8":0,"9":0,"10":0,"11":0,"12":0}
into an array of key-value pairs like this:
[[1,5],[2,7],[3,0],[4,0]...].
How can I convert an Object to an Array of key-value pairs in JavaScript?
You can use Object.keys() and map() to do this
var obj = {"1":5,"2":7,"3":0,"4":0,"5":0,"6":0,"7":0,"8":0,"9":0,"10":0,"11":0,"12":0}
var result = Object.keys(obj).map((key) => [Number(key), obj[key]]);
console.log(result);
The best way is to do:
var obj = {"1":5,"2":7,"3":0,"4":0,"5":0,"6":0,"7":0,"8":0,"9":0,"10":0,"11":0,"12":0}
var result = Object.entries(obj);
console.log(result);
Calling entries, as shown here, will return [key, value] pairs, as the caller requested.
Alternatively, you could call Object.values(obj), which would return only values.
Object.entries() returns an array whose elements are arrays corresponding to the enumerable property [key, value] pairs found directly upon object. The ordering of the properties is the same as that given by looping over the property values of the object manually.
- https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/entries#Description
The Object.entries function returns almost the exact output you're asking for, except the keys are strings instead of numbers.
const obj = {"1":5,"2":7,"3":0,"4":0,"5":0,"6":0,"7":0,"8":0,"9":0,"10":0,"11":0,"12":0};
console.log(Object.entries(obj));
If you need the keys to be numbers, you could map the result to a new array with a callback function that replaces the key in each pair with a number coerced from it.
const obj = {"1":5,"2":7,"3":0,"4":0,"5":0,"6":0,"7":0,"8":0,"9":0,"10":0,"11":0,"12":0};
const toNumericPairs = input => {
const entries = Object.entries(input);
return entries.map(entry => Object.assign(entry, { 0: +entry[0] }));
}
console.log(toNumericPairs(obj));
I use an arrow function and Object.assign for the map callback in the example above so that I can keep it in one instruction by leveraging the fact that Object.assign returns the object being assigned to, and a single instruction arrow function's return value is the result of the instruction.
This is equivalent to:
entry => {
entry[0] = +entry[0];
return entry;
}
As mentioned by #TravisClarke in the comments, the map function could be shortened to:
entry => [ +entry[0], entry[1] ]
However, that would create a new array for each key-value pair, instead of modifying the existing array in place, hence doubling the amount of key-value pair arrays created. While the original entries array is still accessible, it and its entries will not be garbage collected.
Now, even though using our in-place method still uses two arrays that hold the key-value pairs (the input and the output arrays), the total number of arrays only changes by one. The input and output arrays aren't actually filled with arrays, but rather references to arrays and those references take up a negligible amount of space in memory.
Modifying each key-value pair in-place results in a negligible amount of memory growth, but requires typing a few more characters.
Creating a new array for each key-value pair results in doubling the amount of memory required, but requires typing a few less characters.
You could go one step further and eliminate growth altogether by modifying the entries array in-place instead of mapping it to a new array:
const obj = {"1":5,"2":7,"3":0,"4":0,"5":0,"6":0,"7":0,"8":0,"9":0,"10":0,"11":0,"12":0};
const toNumericPairs = input => {
const entries = Object.entries(obj);
entries.forEach(entry => entry[0] = +entry[0]);
return entries;
}
console.log(toNumericPairs(obj));
To recap some of these answers now on 2018, where ES6 is the standard.
Starting with the object:
let const={"1":9,"2":8,"3":7,"4":6,"5":5,"6":4,"7":3,"8":2,"9":1,"10":0,"12":5};
Just blindly getting the values on an array, do not care of the keys:
const obj={"1":9,"2":8,"3":7,"4":6,"5":5,"6":4,"7":3,"8":2,"9":1,"10":0,"12":5};
console.log(Object.values(obj));
//[9,8,7,6,5,4,3,2,1,0,5]
Simple getting the pairs on an array:
const obj={"1":9,"2":8,"3":7,"4":6,"5":5,"6":4,"7":3,"8":2,"9":1,"10":0,"12":5};
console.log(Object.entries(obj));
//[["1",9],["2",8],["3",7],["4",6],["5",5],["6",4],["7",3],["8",2],["9",1],["10",0],["12",5]]
Same as previous, but with numeric keys on each pair:
const obj={"1":9,"2":8,"3":7,"4":6,"5":5,"6":4,"7":3,"8":2,"9":1,"10":0,"12":5};
console.log(Object.entries(obj).map(([k,v])=>[+k,v]));
//[[1,9],[2,8],[3,7],[4,6],[5,5],[6,4],[7,3],[8,2],[9,1],[10,0],[12,5]]
Using the object property as key for a new array (could create sparse arrays):
const obj={"1":9,"2":8,"3":7,"4":6,"5":5,"6":4,"7":3,"8":2,"9":1,"10":0,"12":5};
console.log(Object.entries(obj).reduce((ini,[k,v])=>(ini[k]=v,ini),[]));
//[undefined,9,8,7,6,5,4,3,2,1,0,undefined,5]
This last method, it could also reorganize the array order depending the value of keys. Sometimes this could be the desired behaviour (sometimes don't). But the advantage now is that the values are indexed on the correct array slot, essential and trivial to do searches on it.
Map instead of Array
Finally (not part of the original question, but for completeness), if you need to easy search using the key or the value, but you don't want sparse arrays, no duplicates and no reordering without the need to convert to numeric keys (even can access very complex keys), then array (or object) is not what you need. I will recommend Map instead:
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map
let r=new Map(Object.entries(obj));
r.get("4"); //6
r.has(8); //true
In Ecmascript 6,
var obj = {"1":5,"2":7,"3":0,"4":0,"5":0,"6":0,"7":0,"8":0,"9":0,"10":0,"11":0,"12":0};
var res = Object.entries(obj);
console.log(res);
var obj = {
"1": 5,
"2": 7,
"3": 0,
"4": 0,
"5": 0,
"6": 0,
"7": 0,
"8": 0,
"9": 0,
"10": 0,
"11": 0,
"12": 0
};
var res = Object.entries(obj);
console.log(res);
Yet another solution if Object.entries won't work for you.
const obj = {
'1': 29,
'2': 42
};
const arr = Array.from(Object.keys(obj), k=>[`${k}`, obj[k]]);
console.log(arr);
Use Object.keys and Array#map methods.
var obj = {
"1": 5,
"2": 7,
"3": 0,
"4": 0,
"5": 0,
"6": 0,
"7": 0,
"8": 0,
"9": 0,
"10": 0,
"11": 0,
"12": 0
};
// get all object property names
var res = Object.keys(obj)
// iterate over them and generate the array
.map(function(k) {
// generate the array element
return [+k, obj[k]];
});
console.log(res);
Use Object.entries to get each element of Object in key & value format, then map through them like this:
var obj = {"1":5,"2":7,"3":0,"4":0,"5":0,"6":0,"7":0,"8":0,"9":0,"10":0,"11":0,"12":0}
var res = Object.entries(obj).map(([k, v]) => ([Number(k), v]));
console.log(res);
But, if you are certain that the keys will be in progressive order you can use Object.values and Array#map to do something like this:
var obj = {"1":5,"2":7,"3":0,"4":0,"5":0,"6":0,"7":0,"8":0,"9":0,"10":0,"11":0,"12":0};
// idx is the index, you can use any logic to increment it (starts from 0)
let result = Object.values(obj).map((e, idx) => ([++idx, e]));
console.log(result);
You can use Object.values([]), you might need this polyfill if you don't already:
const objectToValuesPolyfill = (object) => {
return Object.keys(object).map(key => object[key]);
};
Object.values = Object.values || objectToValuesPolyfill;
https://stackoverflow.com/a/54822153/846348
Then you can just do:
var object = {1: 'hello', 2: 'world'};
var array = Object.values(object);
Just remember that arrays in js can only use numerical keys so if you used something else in the object then those will become `0,1,2...x``
It can be useful to remove duplicates for example if you have a unique key.
var obj = {};
object[uniqueKey] = '...';
With lodash, in addition to the answer provided above, you can also have the key in the output array.
Without the object keys in the output array
for:
const array = _.values(obj);
If obj is the following:
{ “art”: { id: 1, title: “aaaa” }, “fiction”: { id: 22, title: “7777”} }
Then array will be:
[ { id: 1, title: “aaaa” }, { id: 22, title: “7777” } ]
With the object keys in the output array
If you write instead ('genre' is a string that you choose):
const array= _.map(obj, (val, id) => {
return { ...val, genre: key };
});
You will get:
[
{ id: 1, title: “aaaa” , genre: “art”},
{ id: 22, title: “7777”, genre: “fiction” }
]
If you are using lodash, it could be as simple as this:
var arr = _.values(obj);
var obj = { "1": 5, "2": 7, "3": 0, "4": 0, "5": 0, "6": 0, "7": 0, "8": 0, "9": 0, "10": 0, "11": 0, "12": 0 }
let objectKeys = Object.keys(obj);
let answer = objectKeys.map(value => {
return [value + ':' + obj[value]]
});
const persons = {
john: { age: 23, year:2010},
jack: { age: 22, year:2011},
jenny: { age: 21, year:2012}
}
const resultArray = Object.keys(persons).map(index => {
let person = persons[index];
return person;
});
//use this for not indexed object to change array
This is my solution, i have the same issue and its seems like this solution work for me.
yourObj = [].concat(yourObj);
or you can use Object.assign():
const obj = { 0: 1, 1: 2, 2: 3};
const arr = Object.assign([], obj);
console.log(arr)
// arr is [1, 2, 3]
Here is a "new" way with es6 using the spread operator in conjunction with Object.entries.
const data = {"1":5,"2":7,"3":0,"4":0,"5":0,"6":0,"7":0,"8":0,"9":0,"10":0,"11":0,"12":0};
const dataSpread = [...Object.entries(data)];
// data spread value is now:
[
[ '1', 5 ], [ '2', 7 ],
[ '3', 0 ], [ '4', 0 ],
[ '5', 0 ], [ '6', 0 ],
[ '7', 0 ], [ '8', 0 ],
[ '9', 0 ], [ '10', 0 ],
[ '11', 0 ], [ '12', 0 ]
]
you can use 3 methods convert object into array (reference for anyone not only for this question (3rd on is the most suitable,answer for this question)
Object.keys() ,Object.values(),andObject.entries()
examples for 3 methods
use Object.keys()
const text= {
quote: 'hello world',
author: 'unknown'
};
const propertyNames = Object.keys(text);
console.log(propertyNames);
result
[ 'quote', 'author' ]
use Object.values()
const propertyValues = Object.values(text);
console.log(propertyValues);
result
[ 'Hello world', 'unknown' ]
use Object.entires()
const propertyValues = Object.entires(text);
console.log(propertyValues);
result
[ [ 'quote', 'Hello world' ], [ 'author', 'unknown' ] ]
Use for in
var obj = { "10":5, "2":7, "3":0, "4":0, "5":0, "6":0, "7":0,
"8":0, "9":0, "10":0, "11":0, "12":0 };
var objectToArray = function(obj) {
var _arr = [];
for (var key in obj) {
_arr.push([key, obj[key]]);
}
return _arr;
}
console.log(objectToArray(obj));
Recursive convert object to array
function is_object(mixed_var) {
if (mixed_var instanceof Array) {
return false;
} else {
return (mixed_var !== null) && (typeof( mixed_var ) == 'object');
}
}
function objectToArray(obj) {
var array = [], tempObject;
for (var key in obj) {
tempObject = obj[key];
if (is_object(obj[key])) {
tempObject = objectToArray(obj[key]);
}
array[key] = tempObject;
}
return array;
}
We can change Number to String type for Key like below:
var obj = {"1":5,"2":7,"3":0,"4":0,"5":0,"6":0,"7":0,"8":0,"9":0,"10":0,"11":0,"12":0}
var result = Object.keys(obj).map(function(key) {
return [String(key), obj[key]];
});
console.log(result);
you can use _.castArray(obj).
example:
_.castArray({ 'a': 1 });
// => [{ 'a': 1 }]

how to add parents name in an object (got parent count )

I am trying to make a object in which it property have parent count and parent names. I am able to count the parents ..But I want to add the parent name in my code..
Here is my code
https://jsfiddle.net/ood2ezvz/11/
Code
function getParentCount(nodes) {
var parent = {}, o = {};
nodes.forEach(function (n) {
parent[n.node_from] = parent[n.node_from] || [];
n.children.forEach(function (a) {
parent[a.node_to] = parent[a.node_to] || [];
parent[a.node_to].push(n.node_from);
});
});
Object.keys(parent).forEach(function (k) { o[k] = parent[k].length; });
return o;
}
my output
{11: 0, 12: 1, 13: 1, 14: 1, 15: 2, 16: 1, 17: 1, 18: 1, 19: 1}
Expected out put
{
11:{count:0,parent:[]},
12:{count:1,parent:['11']},
13:{count:1,parent:['12']},
14:{count:1,parent:['13']},
15:{count:2,parent:['13','14']},
16:{count:1,parent:['15']},
17:{count:1,parent:['15']},
18:{count:1,parent:['15']},
19:{count:1,parent:['18']},
}
Try to replace :
Object.keys(parent).forEach(function (k) { o[k] = parent[k].length; });
By :
Object.keys(parent).forEach(function (k) {
o[k] = {};
o[k]['count'] = parent[k].length;
o[k]['parent'] = parent[k];
});
I'd suggest converting your structure to something more usable. Since it seems to be a directed graph, a natural representation will be the list of pairs [from, to]:
graph = []
node.forEach(n =>
n.children.forEach(c =>
graph.push([n.node_from, c.node_to])
)
)
Now you can easily find preceding and following nodes for every given node:
nodes_from = n => graph.filter(v => v[0] === n).map(v => v[1])
console.log(nodes_from(15)) // [ 16, 17, 18 ]
nodes_to = n => graph.filter(v => v[1] === n).map(v => v[0])
console.log(nodes_to(15)) // [ 13, 14 ]

Categories

Resources