How to shift values through the keys of an array-like object? - javascript

For an array I can do:
array.push(array.shift())
var array = [0, 1, 2, 3, 4, 5];
array.push(array.shift())
console.log(array); // [1, 2, 3, 4, 5, 0]
How can I do the same for an object?
Input
var object = {0: 'Fiat', 1: 'Audi', 2: 'BMW', 3: 'Citroën'}
How can I move {0: 'Fiat'} to the end of the object
Expected output:
{0: 'Audi', 1: 'BMW', 2: 'Citroën', 3: 'Fiat'}

You can use the following way
var object = {0: 'Fiat', 1: 'Audi', 2: 'BMW', 3: 'Citroën'};
var result = Object.keys(object).map(e => object[e]);
//console.log(result);
result.push(result.shift());
//console.log(result);
let ans = Object.assign({}, result);
console.log(ans);

You could convert you object with the given keys as index to an array, apply the shifting and convert back to an object.
var object = { 0: 'Fiat', 1: 'Audi', 4: 'BMW', 5: 'Citroën' },
array = Object.keys(object).reduce((r, k, i) => (r[i] = object[k], r), []);
array.push(array.shift());
console.log(Object.assign({}, array)); // { 0: "Audi", 1: "BMW", 2: "Citroën", 3: "Fiat" }
A different approach, while respecting the keys.
var object = { 0: 'Fiat', 1: 'Audi', 4: 'BMW', 5: 'Citroën' },
keys = Object.keys(object);
result = Object.assign(...keys.map((k, i) => ({ [k]: object[keys[(i + 1) % keys.length]] })));
console.log(result); // { 0: "Audi", 1: "BMW", 4: "Citroën", 5: "Fiat" }

The object's properties does not have any guarantee on the order, in which they may appear, concise there is no concept as order. I think you need to think more and can find another solution, which does not depend on the properties order.

You can convert your object into an array, do the reordering on the array and convert the array back to an object:
function toObject(arr) {
var rv = {};
for (var i = 0; i < arr.length; ++i)
rv[i] = arr[i];
return rv;
}
function toArray(object) {
return Object.keys(object).map(function (key) { return object[key]; });
}
var object = {0: 'Fiat', 1: 'Audi', 2: 'BMW', 3: 'Citroën'}
var array = toArray(object);
array.push(array.shift());
object = toObject(array);
console.log(object);

You should not rely on ordering of object's keys in JavaScript. It's not defined by standard. Objects by definition do not have an ordering, so there is no "end" of the object. It simply doesn't make sense to "move" a key of an object anywhere, since there's no ordering.
The data-structure which does have orders are arrays.
Your object is almost array-like, because all of its keys are consecutive numbers, but it's missing a lenght property. With length, you could turn it into an actual array with Array.from(object).

As Suren said, the object does not guarantee the insertion order. I suggest another approach for example:
const o = {0: 'Fiat', 1: 'Audi', 2: 'BMW', 3: 'Citroën'};
const k = Object.keys(o);
k.push(k.shift());
const result = k.map((v, i) => ({[i]: o[v]}))
.reduce((acum, v) => Object.assign(acum, v), {});
The approach here is to create and index array, apply the logic (push and shift) then re-build the object with map, and then merge them into one object with reduce. I think this could be shorter (just the reduce) but i wanted to split this up to be more clear.

Teaching: Objects are usually based on a Hash table for lookup by key.
As a consequence this usually means you do not have order.
myObj[key] => find value by computing hash of key => returns value

Related

Making an array from two another

I have two arrays of objects (10 objects in each arrray) ->
arr1 = [{name: '', age: ''}...]
and
arr2 = [{surname: '', position: ''}...]
which I hold in two separated states.
My goal is to create the third array of the objects which contains also 10 elements
arr3=[{name: arr1.name, surname: arr2.surname}...]
How can I do this ?
As long as it is a 1 to 1 where each index matches, it is a simple Array map and using the spread to copy over the properties and values.
const arr1 = [{a: 1, b: 2}, {a: 3, b: 4}];
const arr2 = [{c: 11, d: 22}, {c: 33, d: 44}];
const arr3 = arr1.map((obj, ind) => ({...obj, ...arr2[ind]}), []);
console.log(arr3);
This is what you need,
let arr3 = []
arr1.forEach((obj1, index) => {
let obj3 = {...obj1, ...arr2[index]}
arr3.push(obj3)
})
If the indexes are assumed to match between the two arrays (which also implies that the two arrays are the same length), you can use map() on one array and use its index parameter to reference the other array. (It doesn't really matter which.)
For example:
const arr3 = arr1.map((a, i) => ({
name: a.name,
surname: arr2[i].surname
}));
Note that this is based on the example shown, where only two properties (one from each array) are in the resulting objects. If you want all properties in the resulting objects, you don't need to specify all of them. You can just combine them all:
const arr3 = arr1.map((a, i) => ({
...a,
...arr2[i]
}));
Here is how you could combine both arrays using a for loop:
const arr3 = []
for (let i = 0; i < arr1.length; i++) {
arr3[i] = {
name: arr1[i].name,
surname: arr2[i].surname
}
}
I don't get exactly what do you want to do but I think this question has been answered a few times.
You wanna do arr1 + arr2 ? Like they follow each others in the array3 ?

Remove values from subarrays javascript

Having some difficulty removing the row 0 in all my subarrays
Tried splice as well but can't seem to find a good example that remove values from subarrays.
Arr1
// This is how my main Arr1 looks like
(3) [Array(2), Array(2), ...]
0: (2) ["2021-07-06T00:00:00Z", {…}]
1: (2) ["2021-07-06T00:00:00Z", {…}]
...
// Which will have multiple subarrays when the main array is expanded
0: Array(2)
0: "2021-07-06T00:00:00Z"
1: {type: "meeting", id: "123"}
1: Array(2)
0: "2021-07-06T00:00:00Z"
1: {type: "call", id: "456"}
....
End result - Remove row 0, which is the date & time from each array and combine all of them together
0: {type: "meeting", id: "123"}
1: {type: "call", id: "456"}
Since you have nested arrays you will have to combine map and filter. Map to iterate the top level and filter or splice (depending on your logic) - on the sub to remove or filter out items.
topArray.map(subArray => subArray.filter(item => ...))
or
topArray.map(subArray => subArray.splice(start, deleteCount)
If you then want to "flatten" the results you can add .flat() or .flatMap() to the end (depending on your logic)
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array
If you know that you just want to grab the first item on each sub-array, you can:
topArray.map(subArray => subArray[0])
I would personnaly recommand using map which here takes for each element in your array, the second element (which is your object)
const arr = [
["2021-07-06T00:00:00Z", {type:"meeting",id:"123"}],
["2021-08-06T00:00:00Z", {type: "call", id: "456"}],
["2021-09-06T00:00:00Z", {type: "zoom", id: "789"}]
];
console.log(arr.map(item => item[1]))
Here's how you can do it:
let result = [];
let arr = [
["2021-07-06T00:00:00Z", {type:"meeting",id:"123"}],
["2021-07-06T00:00:00Z", {type: "call", id: "456"}]
];
result = arr.map((item)=>{
return item[1];
})
console.log(result);
You can use a slice to remove the first element of each subarray. And a flatMap to join all the filtered subarrays into one single array.
Here's how I would do it:
const filteredArray = array.flatMap((subarray) => subarray.slice(1));
use Map with filter
var a = [[1,2], [3,4]]
console.log(a.map((b) => b.filter((c, i) => i != 0)))
Result
[[2], [4]]

In Javascript remove keys from object not in an Array

Suppose I have a list of objects with many keys and I want to keep only certain keys from them.
This is how I am doing it.
The Problem with other good solutions on SO are that if a key is not present in the keys to keep it still adds a key, value where the value is undefined.
let data = [{
'a': 1,
'b': 2,
'c': 3
},
{
'a': 1,
'c': 3,
'd': 4
}]
const keys_to_keep = ['a', 'b']
data = data.map((obj) => {
Object.keys(obj).forEach(function(key) {
if(!keys_to_keep.includes(key))
delete obj[key]
});
return obj;
})
Output :
[ { a: 1, b: 2 }, { a: 1} ]
Is there a better way to get this done.
Any help is appreciated.
A couple of improvements.
You're using .map() which creates a new array, but then you're just assigning it to the old variable. So, you apparently don't need to create a new array at all, you can just iterate the one you have and modify it.
Put the properties you want to keep in a Set instead of an Array for potentially faster lookup.
for/of loops are generally favored over .forEach() loops because of better flow control options (break, continue, return, etc...) and more opportunities for compiler optimization.
let kv = [{
'a': 1,
'b': 2,
'c': 3
},
{
'a': 1,
'b': 2,
'c': 3,
'd': 4
}]
const l = new Set(['a', 'b']);
for (let obj of kv) {
for (let prop of Object.keys(obj)) {
if (!l.has(prop)) {
delete obj[prop];
}
}
}
console.log(kv);
You can use Object.fromEntries, after map and filter to keep only the relevant keys:
let data = [{'a': 1,'b': 2,'c': 3},{'a': 1,'c': 3,'d': 4}]
const keys_to_keep = ['a', 'b']
var result = data.map(obj =>
Object.fromEntries(keys_to_keep.map(key =>
obj.hasOwnProperty(key) && [key, obj[key]]
).filter(Boolean))
);
console.log(result);

How to transform an array to an object [duplicate]

This question already has answers here:
How to convert an array of objects to object with key value pairs
(7 answers)
How to convert an array of key-value tuples into an object
(14 answers)
Closed 5 years ago.
I would like to turn this:
let myArray = [ {city: "NY"}, {status: 'full'} ];
to this:
let myObj = { city: "NY", status: 'full' };
while I tried this:
let newObj = {};
for (var i = 0; i < myArray.length; i++) {
(function(x) {
newObj = Object.assign(myArray[i]);
})(i);
}
it assigns the last pair to the object
Spread the array into Object#assign:
const myArray = [ {city: "NY"}, {status: 'full'} ];
const myObj = Object.assign({}, ...myArray);
console.log(myObj);
Note: Assign into an empty object. If you omit the empty object, the 1st element of the original array will be mutated (everything will be merged into it).
You could also use Array.reduce() which will give you more fine grain control:
const myArray = [
{ city: 'NY', color: 'blue', rodents: { small: false, medium: false, large: true } },
{ status: 'full', color: 'red' },
{ sandwich: 'flavourful' },
]
// item is each object in your array
const reduced = myArray.reduce((newObj, item) => {
// existing props will be overwritten by newer object entries in the array
// this example is same as Object.assign spread with right to left precedence,
// until you want more custom logic
Object.keys(item).forEach((key) => { newObj[key] = item[key] })
return newObj
}, {})
console.log(reduced)
// you will see `red` overwrite `blue`
EDIT: after examining this answer after a year, I note that it isn't optimized at all for ability to deep clone or deep merge. I recommend studying those aspects closer and to be careful of copying or breaking references if you are working immutably.
There is no issue with this in the above example because all values are primitives.
I would tend to agree with Ori that your question seems to be about creating an indexed object which isn't usually a good plan, but if its necessary to key your object with numbers you can do it like this:
let newObj = {};
myArray.forEach((val, index) => { newObj[index] = val });
let myArray = [ {city: "NY"}, {status: 'full'} ];
let newObj = myArray.reduce((acc, curr) => {
Object.keys(curr).forEach(val => {
acc[val] = curr[val]
})
return acc
}, {})
console.log(newObj)
This syntax is supported in IE according to caniuse.com

How to convert key-value pair object into an array of values in ES6?

I'm developing a React application where I need to convert a key-value object like this:
{
0: 'John',
1: 'Tim',
2: 'Matt'
};
To an array of just the values like this:
['John', 'Tim', 'Matt']
How do I accomplish this?
const obj = {
0: 'John',
1: 'Tim',
2: 'Matt'
};
const arr = /* ??? */;
You could use Object.values.
The Object.values() method returns an array of a given object's own enumerable property values, in the same order as that provided by a for...in loop (the difference being that a for-in loop enumerates properties in the prototype chain as well).
var object = { 0: 'John', 1: 'Tim', 2: 'Matt' },
array = Object.values(object);
console.log(array);
With ES6, you could use Array.from and use a callback for the values.
var object = { 0: 'John', 1: 'Tim', 2: 'Matt' },
array = Array.from(Object.keys(object), k => object[k]);
console.log(array);
You can make use of Object.values command.
According to the docs.
Object.values() returns an array whose elements are the enumerable
property values found on the object. The ordering of the properties is
the same as that given by looping over the property values of the
object manually
Although it is an ES2017 solution but since you are using react, you can include stage-0 as a preset for babel and access this functionality
var data ={
0: 'John',
1: 'Tim',
2: 'Matt'
};
var newdata = Object.values(data);
console.log(newdata);
there are other methods like Object.keys which gives you all the keys as an array and Object.entries method returns an array of a given object's own enumerable property [key, value] pairs which might also be useful to you
const obj = {
0: 'John',
1: 'Tim',
2: 'Matt'
};
const arr = [];
for(let key in obj){
arr.push(obj[key]);
}
While you have numerical keys and in an order without gaps, you could use Object.assign with an array as target and the given object as source.
var object = { 0: 'John', 1: 'Tim', 2: 'Matt' },
array = Object.assign([], object);
console.log(array);
This is commonly used one:
const obj={
1:'Azamat',
2: 'Kanybek',
3: 'Manas'}
console.log(Object.values(obj))
for key, value pairs:
const arr = [];
for(let key in obj){
arr.push([key,obj[key]])
}
console.log(arr)

Categories