Reputation: 3750
I have a question that I believe is straightforward, but I've seen conflicting answers on.
Let's say I have the following data structure:
const data = [
...,
{
someKey: [
...,
{
someDeepKey: [
...,
'two'
],
}
]
}
]
So accessing the first index of all of the following would look like this:
data[0].someKey[0].someDeepKey[0]
But if I wanted to find the LAST index of all of these, I haven't found a clean method. I have seen some people recommend extending the Array prototype itself, which I feel is a bad idea.
The only other "clean" solution I can think of is to chain down variables to make it semi readable.
let someKey = data[data.length - 1].someKey
let someDeepKey = someKey[someKey.length - 1].someDeepKey
let someDeepKeyValue = someDeepKey[someDeepKey.length - 1]
Can anybody suggest a cleaner way to do this? I believe Python supports something neat such as:
data[-1].someKey[-1].someDeepKey[-1]
and I was wondering if there is anything similar in JS.
Upvotes: 3
Views: 66
Reputation: 3750
I did happen to stumble upon this. It appears to do what I want without mutating the original array, much cleaner than doing the whole .length - 1
chain:
let data = [
{
someKey: [
{
someOtherKey: [
'Fake',
'Name'
]
}
]
}
];
let name = data.slice(-1).pop()
.someKey.slice(-1).pop()
.someOtherKey.slice(-1).pop();
console.log(name) // 'Name'
console.log(data) // Original data
Unsure how performant it is, but its certainly at least a lot more readable and it grabs the end values needed.
Probably a performance nightmare since its making so many copies in memory, but when we're just dealing with smaller datasets, I think this fits the bill to snag accurate values in deeply nested arrays without mutating anything.
Ran some evaluations. Here are some basic tests here:
// Scaffold a dataset
let dataSet = [];
for (let i = 0; i < 100; i++) {
let someObj = {
someKey: []
}
for (let j = 0; j < 100; j++) {
let someOtherObj = {
someOtherKey: []
}
for (let k = 0; k < 1000; k++) {
someOtherObj.someOtherKey.push(k)
}
someObj.someKey.push(someOtherObj)
}
dataSet.push(someObj)
}
const slicePop = (data) => {
// Slice Pop
let start = window.performance.now();
let name = data.slice(-1).pop()
.someKey.slice(-1).pop()
.someOtherKey.slice(-1).pop();
let end = window.performance.now();
let time = end - start;
return time
}
const spreadPop = (data) => {
// Spread Pop
let start = window.performance.now();
let name = [...[...[ ...data ].pop().someKey].pop().someOtherKey].pop()
let end = window.performance.now();
let time = end - start;
return time
}
const lastMethod = (data) => {
// Function
let start = window.performance.now();
const last = (arr) => arr[arr.length - 1]
let name = last(last(last(data).someKey).someOtherKey)
let end = window.performance.now();
let time = end - start;
return time
}
const variables = (data) => {
let start = window.performance.now();
let someKey = data[data.length - 1].someKey
let someOtherKey = someKey[someKey.length - 1].someOtherKey
let name = someOtherKey[someOtherKey.length - 1]
let end = window.performance.now();
let time = end - start;
return time
}
const lastDeep = (arr) => {
let start = window.performance.now();
let name = ['someKey', 'someOtherKey', ''].reduce(
(last, cur) => (
(res = last[last.length - 1]),
res[cur] ? res[cur] : undefined
),arr)
let end = window.performance.now();
let time = end - start;
return time
}
let slicePopTimes = [];
let spreadPopTimes = [];
let lastMethodTimes = [];
let variablesTimes = [];
let reduceTimes = [];
for (let i = 0; i < 100; i++) {
slicePopTimes.push(slicePop(dataSet))
}
for (let i = 0; i < 100; i++) {
spreadPopTimes.push(spreadPop(dataSet))
}
for (let i = 0; i < 100; i++) {
lastMethodTimes.push(lastMethod(dataSet))
}
for (let i = 0; i < 100; i++) {
variablesTimes.push(variables(dataSet))
}
for (let i = 0; i < 100; i++) {
reduceTimes.push(lastDeep(dataSet))
}
const getAvg = (arr) => {
let total = arr.reduce((acc, i) => {
acc += i
return acc
}, 0);
return ((total / arr.length) * 1000)
}
let results = {
slicePopTime: getAvg(slicePopTimes),
spreadPopTime: getAvg(spreadPopTimes),
lastMethodTime: getAvg(lastMethodTimes),
variablesTime: getAvg(variablesTimes),
reduceTime: getAvg(reduceTimes)
}
console.log('RESULTS', results)
Upvotes: 2
Reputation: 11001
Here small util using reduce
, will be handy and works for any level of nesting.
const data = [
{
someKey: [
{
someDeepKey: ["one"],
},
],
},
{
someKey: [
{
someDeepKey: ["one", "two"],
},
],
},
];
const lastDeep = ["someKey", "someDeepKey", ""].reduce(
(last, cur) => ((res = last[last.length - 1]), res[cur] ?? res),
data
);
console.log(lastDeep);
Upvotes: 2
Reputation: 151
Define a function named last to get last element of an array and use it like this last(last(last(data).someKey).someDeepKey)
.
Upvotes: 1
Reputation: 5051
you can following this code
let x = [...[...[ ...data ].pop().someKey].pop().someDeepKey].pop()
Upvotes: 1