Deleting element from OrderedMap and keeping its order - javascript

I want to create Map which has key and value, and keep order of elements inside of it.
That order defines an order of displaying elements on the screen.
Also, I want to have possibility to delete one of the elements and keep their order.
And the most important think I'm using immutable.js library and I want to use it. Can I do it with that library?
That is what I tested:
const { OrderedMap } = require("immutable");
let test = OrderedMap({
a: 10,
b: 20,
c: 30,
d: 40
});
test = test.delete('b');
console.log(test);
And it prints me this:
I was expecting a, c, d order but i get a, d, c.
UPDATED
Here is a JSFiddle
How can I fix it?

I created a repo to reproduce your issue, but was unable to.
I added a console.log() before deleting the item, to make sure test had keys in the right order before I modified it. Here is my output:
~/code/src/github.com/asday/immutablejs-delete-from-ordered-map $ node index.js
OrderedMap { "a": 10, "b": 20, "c": 30, "d": 40 }
OrderedMap { "a": 10, "c": 30, "d": 40 }
It's possible that the environment you're running the code in is not respecting the order of the keys provided to OrderedMap(). If this is the case, try instantiating it with an array of [key, value] pairs:
let test = OrderedMap([
['a', 10],
['b', 20],
['c', 30],
['d', 40],
]);
And see if that fixes your issue.
EDIT: Your problem is you're attempting to use the internals of the OrderedMap, whereas you should be using methods defined on it. The order of what's in ._map is irrelevant, as you can see:
> test.toString()
"OrderedMap { "a": 10, "c": 30, "d": 40 }"
If you want to iterate over your values in order, you should use .map() like so:
test.map((x) => console.log(x))
Or:
test.mapEntries((x) => console.log(x[0], x[1]))

Related

Array sorting for Object Keys not working

Could someone please help me sort object by key with given array?
given array ['NAME',20200229,20200131,20200331]
given object {20200131: 51, 20200229: 50, 20200331: 170, NAME: "a"}
Object.fromEntries was expected to build object in the given keys
Object.fromEntries(Object.entries({b: 3, a:8, c:1}))
//{b: 3, a: 8, c: 1} <-- works fine
But when I try with keys that has number and alphanumerics it's doesn't work
let sortingArr = ['NAME',20200229,20200131,20200331] // desired sort, for example
// All below gives the same result
Object.fromEntries(Object.entries({NAME: 'a',20200131: 51, 20200229: 50, 20200331: 170}))
// sort asc naturally,.. ok
Object.fromEntries(Object.entries({NAME: 'a',20200131: 51, 20200229: 50, 20200331: 170}).sort())
// sort asc naturally,.. redundant... ok, no problems
Object.fromEntries(Object.entries({NAME: 'a',20200131: 51, 20200229: 50, 20200331: 170}).sort((a, b)=> parseInt(a)||0 + sortingArr.indexOf(b)))
//Problem! was supose to consider the sorting logic*, right?
//*Sorting works: Object.entries({NAME: 'a',20200131: 51, 20200229: 50, 20200331: 170}).sort((a, b)=> parseInt(a)||0 + sortingArr.indexOf(b))
//0: ["NAME", "a"]
//1: ["20200131", 51]
//2: ["20200229", 50]
//3: ["20200331", 170]
I read other responses and they are very redundant, with people wanting only in ascending (or descending) order, without the desired array

Is there a way to ensure javascript object properties are ordered in a specific way?

I have a JavaScript object that looks like this:
Const data = {
x: 1,
y: 2,
z: 3
a: 4,
b: 5,
c: 6
};
We have a signing service in our Angular 6 application which stringifies this object, hashes the string, then attached a signature to it. Then it saves it to a firestore database. The database likes to order the properties alphabetically so it ends up looking like this:
{
a: 4,
b: 5,
c: 6,
x: 1,
y: 2,
z: 3
}
When we retrieve this object from the database and try to validate the signature, it fails. It fails because when you stringify this object, the alphabetical order of the properties results in a different string compared to when we signed it. This results in a different hash which doesn’t match with the original signature.
Our current solution to this problem is that we write out the order of the properties alphabetically in the code, but we’d like to make this fool proof (ex. If another developer comes along and adds a property to the bottom, say d, not realizing it’s supposed to be alphabetical). I’m told by a colleague that there is some way of telling Javascript to order the properties according to its own algorithm. If we could do that, then we’d order the properties according to that algorithm before stringifying, hashing, and signing, and then when we retrieve the object from the database, do the same thing: order the properties according to Javascript’s algorithm, stringify, hash, and validate.
Does anyone know what this Javascript ordering is and how to do it?
There isn't a way for JS to naturally order an object, you're going to have to tinker with it yourself.
The easiest way that I can think of to do this would be to use an array and sort from there.
This will return you the following array...
Object.entries(test).sort((a, b) => a[1] - b[1])
returns
[ [ 'x', 1 ],
[ 'y', 2 ],
[ 'z', 3 ],
[ 'a', 4 ],
[ 'b', 5 ],
[ 'c', 6 ] ]
If you want it back in an object,
Object.assign({}, ...Object.entries(test).sort((a, b) => a[1] - b[1]).map(([key, value]) => ({[key]: value})) )
returns
{ x: 1, y: 2, z: 3, a: 4, b: 5, c: 6 }
Create a custom stringify function that handles putting the object in the correct order.
const data = {
a: 4,
b: 5,
c: 6,
x: 1,
y: 2,
z: 3
}
function customStringify(d){
return '{'+Object
.entries(d)
.sort(([,v1],[,v2])=>v1-v2)
.map(([k,v])=>`${k}:${v}`)
.join(",")+'}';
}
const res = customStringify(data);
console.log(res);

Javascript array includes

I'm trying to figure out if a array contains a specific index or not using the following codelines:
var array1 = [{ "abc": 123, "def": [{"a": 1, "b": 2, "c": 3}, {"a": 3, "b": 2, "c": 1}]}]
console.log(array1.includes('def'));
The array contains "def" so the console should actually return true if I define the array in the following way:
var array1 = [{ "abc": 123, "def": [{"a": 1, "b": 2, "c": 3}, {"a": 3, "b": 2, "c": 1}]}]
Defining it the other way, like:
var array1 = [{ "abc": 123 }]
should return false.
The code above therefore does not work correctly, does anyone have a idea whats causing it to respond a wrong boolean?
I appreciate any kind of suggestions!
The proper method would be array1.some(n => n.hasOwnProperty('def')). See that there is no def in array, but rather object that contains def property
Array.includes returns a boolean based on whether (x) is a value in the given Array, not keys. If you want array1.includes('def') to return the other parts then you must do Object.keys(array1[0]).includes('def')
That is because you do not indicate array you think of.
If you console.log
Object.getOwnPropertyNames(array1), array1 is an array of one object. To get proper result you have to check if the object inside have the def property, so:
array1[0].hasOwnProperty('def') // returns true
The problem here is you try to access an element that is in an object and this object is in a list. To acces the list element, you need to specify its index (here 0). Then you can access the object keys with Object.keys.
var array1 = [{ "abc": 123, "def": [{"a": 1, "b": 2, "c": 3}, {"a": 3, "b": 2, "c": 1}]}]
Object.keys(array1[0]).forEach((element) => {
if(element === "def") console.log(true);
})

Making nodes in a nested Javascript object self aware of their location within the object

I am wondering if there is a good way to get nodes within a deeply nested object to announce their position within the object.
For example, if you were to recursively crawl through the example data below (perhaps with help from a library like Lodash), is there a callback function you could pass to each node that would log the location.
Ideally, this would work at any point in the tree, not just leaf nodes.
i.e. announceLocation(data.b.d[2].j.k[1]) //=> ['b', 'd', '2', 'j', 'k', '1']
let data = {
a: 1,
b: {
c: 2,
d: [
{
e: 3,
f: 4
},
{
g: [5, 6, 7],
h: 8,
i: 9
},
{
j: {
k: [10, 11, 12]
}
}
]
},
l: 13
}
UPDATE:
I haven't tried it out yet, but the npm library js-traverse has a contextual value called this.path that seems to be just what I'm looking for.
JavaScript objects have no defined order, they are (by definition) an unsorted set of key-value pairs.
If however you want to sort the keys by some sorting algorithm you can use the following:
const sortedKeys = Object.keys(myObj).sort(sortingFunction);
You could insert a reference from the parent object into the child object. That way you always have a way of moving to the top of your object.
let groups = {
'1': {
'title': 'Group 1',
'items': {}
}
};
let items = [{ 'group_id': '1', 'id': '1', 'title': 'Item 1' }];
for(let item of items){
item.parent = groups[item.group_id];
groups[item.group_id].items[item.id] = item;
}
console.log(groups['1'].items['1']); // take a look at the parent property

Get list of values from several paths in json object

I have an object with several nested layers of arrays and subobjects, from which I need to extract the values from some paths. Is there some library or native function which can help me do that? I'm already using Lodash and jQuery, but have a hard time figuring out how to simplify this problem.
Example:
{
a: [
{
b: 0,
c: 1
},
{
b: 1,
c: 2
}
]
}
Now I would like to get a list of all a[0..n].b.
My actual object is much larger and has 3 layers of arrays and a path like syn[0].sem[0].pdtb3_relation[0].sense, so I'd rather not write 3 nested for loops if a library function exists.
You can use forEach() to iterate through array.
var o = {
a: [
{
b: 0,
c: 1
},
{
b: 1,
c: 2
}
]
}
Object.keys(o).forEach(a => o[a].forEach(y => console.log(y.b)));

Categories