Home > Software engineering >  How to recursively get access to object values?
How to recursively get access to object values?

Time:11-19

I have an array with recursive objects which looks like this:

export const a: A = [
    {
        person: [
            {
                person: [{
                    person: [],
                    rating: 512,
                    justNumbers: [30, 15, 327]
                },
                    {
                        person: [
                            {
                                person: [],
                                rating: 538,
                                justNumbers: [13, 55, 643]
                            },
                            {
                                person: [],
                                rating: 964,
                                justNumbers: [314, 523, 512]
                            }
                        ],
                        rating: 413,
                        justNumbers: [876, 541, 623]
                    }],
                rating: 176,
                justNumbers: [842, 812,643]
            }
        ],
        rating: 235,
        justNumbers: [33, 565, 73]
    }];

I need to create a function to sum all ratings in recursive way and to create an array of numbers from all numbers in every justNumbers array, which is sorted in ascending order.

  const recursiveNumbersSearch = (obj: object, targetKey: string, getSum = []) => {
    const r = getSum;
    Object.keys(obj).forEach(key => {
        const value: any = obj[key];
        if (key === targetKey && typeof value !== 'object') {
            r.push(value)
        } else if (typeof value === 'object') {
            recursiveNumbersSearch(value, targetKey, r);
        }
    })
    return getSum
}

function sumArray (arr : number[]): number {
    let arraySum: number = 0;
    for (let i = 0; i<= arr.length - 1; i  ) {
        arraySum = arr[i]   arraySum;
    }
    return arraySum;
}

I did this and it counts the sum pretty well, however, there are few compiler errors which are:

Element implicitly has an 'any' type because expression of type 'string' can't be used to index type '{}'.
  No index signature with a parameter of type 'string' was found on type '{}'.

Argument of type 'any' is not assignable to parameter of type 'never'.

First one goes for string:

const value: any = obj[key];

When second one refers to:

r.push(value)

I am a little bit confused, because if I run compiled JS file with node it properly counts the sum, however it does point at those two errors.

From the other hand I am unable to push arrays of justNumbers using the recursiveNumberSearch method.

CodePudding user response:

I think the reason you're having problems with the arrays is because you test typeof value === 'object', but that will be true if value in an Array.

Here, I write what I think is a simpler version of recursiveNumbersSearch, called deepProp. It takes a property name and returns a function that takes an object and does a depth-first traversal, retrieving the named property wherever it's found. We can then use that to layer on simple functions to sum the rating properties or flatten and sort the justNumbers ones, like this:

const deepProp = (prop) => ({[prop]: p, ...rest}) =>
  p == undefined
    ? Object .values (rest) .flatMap (deepProp (prop))
    : [p, ... deepProp (prop) (rest)]

const a = [{person: [{person: [{person: [], rating: 512, justNumbers: [30, 15, 327]}, {person: [{person: [], rating: 538, justNumbers: [13, 55, 643]}, {person: [], rating: 964, justNumbers: [314, 523, 512]}], rating: 413, justNumbers: [876, 541, 623]}], rating: 176, justNumbers: [842, 812, 643]}], rating: 235, justNumbers: [33, 565, 73]}]

console .log (deepProp ('rating') (a))
console .log (deepProp ('justNumbers') (a))

const sum = (ns) => ns .reduce ((a, b) => a   b, 0)

const sumRatings = (o) => sum (deepProp ('rating') (o))
const organizeNumbers = (o) => deepProp ('justNumbers') (o) .flat () .sort ((a, b) => a - b)

console .log (sumRatings (a))
console .log (organizeNumbers (a))
.as-console-wrapper {max-height: 100% !important; top: 0}
<iframe name="sif1" sandbox="allow-forms allow-modals allow-scripts" frameborder="0"></iframe>

I'm afraid I have nothing to offer for your Typescript errors.

  • Related