2

I have an object of objects of a company's hierarchy selection, for example:

{
  1:   { division: "division1" },
  2:   { division: "division2" },
  11:  { division: "division2", branch: "branch2" },
  41:  { division: "division2", branch: "branch2", department: "department2" },
  100: { division: "division2", branch: "branch2", department: "department10" },
  102: { division: "division2", branch: "branch3" },
  130: { division: "division17" },
  144: { division: "division17" , branch: "branch22" },
  200: { division: "division50" }
}

And I need to get the unique objects but most detailed ones. So the above example should result in:

{
  1:   { division: "division1" },
  41:  { division: "division2", branch: "branch2", department: "department2" },
  100: { division: "division2", branch: "branch2", department: "department10" },
  102: { division: "division2", branch: "branch3" },
  144: { division: "division17" , branch: "branch22" },
  200: { division: "division50" }
}

These are selections from 3 dropdowns, each selection holds the data of the entire hierarchy up to that item (The hierarchy is division > branch > department). So if a user selects division2 then branch2, it will add both { division: "division2" } and { division: "division2", branch: "branch2" } but I only need the most detailed one, { division: "division2", branch: "branch2" } in this case.

*Edit: It is not necessary to keep the original keys

How can I do that?

4
  • 2
    what is with the keys in the result? what have you tried? Commented Apr 2, 2023 at 11:17
  • You both are correct, I forgot to set the right keys. and @pilchard I also missed division1, but added now. I hope that clarifies things now. But I will add more info. However you already understood because you corrected me about division1 Commented Apr 2, 2023 at 11:20
  • @NinaScholz I have a solution in PHP which I tried to convert to JS however it did not work for me in JS. I used recursion there Commented Apr 2, 2023 at 11:22
  • @NinaScholz Once the data has been filtered, it is not really important to save the original keys Commented Apr 2, 2023 at 11:27

3 Answers 3

1

You could build a tree with known values and filter the array by looking to values or check the length of the properties.

const
    data = { 1: { division: "division1" }, 2: { division: "division2" }, 11: { division: "division2", branch: "branch2" }, 41: { division: "division2", branch: "branch2", department: "department2" }, 100: { division: "division2", branch: "branch2", department: "department10" }, 100: { division: "division2", branch: "branch3" }, 130: { division: "division17" }, 144: { division: "division17", branch: "branch22" }, 200: { division: "division50" } },
    keys = ['division', 'branch', 'department'],
    tree = Object.values(data).reduce((r, o) => {
        keys.reduce((q, k) => o[k] && (q[o[k]] ??= {}), r);
        return r;
    }, {}),
    result = Object
        .values(data)
        .filter(o => {
            let t = tree;
            return keys.every(k => {
                if (o[k] in t) return t = t[o[k]];
                return !Object.keys(t).length;
            });
        });

console.log(result);
console.log(tree);
.as-console-wrapper { max-height: 100% !important; top: 0; }

If you do not need the original objects, you could build the result set from the tree.

const
    getObjects = (tree, [key, ...keys]) => {
        const entries = Object.entries(tree);
        return entries.length
            ? entries.flatMap(([k, t]) => getObjects(t, keys).map(o => ({ [key]: k, ...o })))
            : [{}];
    },
    data = { 1: { division: "division1" }, 2: { division: "division2" }, 11: { division: "division2", branch: "branch2" }, 41: { division: "division2", branch: "branch2", department: "department2" }, 100: { division: "division2", branch: "branch2", department: "department10" }, 100: { division: "division2", branch: "branch3" }, 130: { division: "division17" }, 144: { division: "division17", branch: "branch22" }, 200: { division: "division50" } },
    keys = ['division', 'branch', 'department'],
    tree = Object.values(data).reduce((r, o) => {
        keys.reduce((q, k) => o[k] && (q[o[k]] ??= {}), r);
        return r;
    }, {}),
    result = getObjects(tree, keys);

console.log(result);
console.log(tree);
.as-console-wrapper { max-height: 100% !important; top: 0; }

Sign up to request clarification or add additional context in comments.

1 Comment

This is really good because it will also work for a different number of dropdowns, not just 3 in my case. Because in reality I do have many pages that require this and they have different number of dropdowns (And different keys). Thank you!
1
let a = {
    1: { division: "division1" },
    2: { division: "division2" },
    11: { division: "division2", branch: "branch2" },
    41: { division: "division2", branch: "branch2", department: "department2" },
    100: { division: "division2", branch: "branch2", department: "department10" },
    102: { division: "division2", branch: "branch3" },
    130: { division: "division17" },
    144: { division: "division17", branch: "branch22" },
    200: { division: "division50" }
}
const aList = Object.values(a) 


// 1. save all into Map by id
const map = new Map();
for (let value of aList) {
    const id = `${value.division} / ${value.branch} / ${value.department}`;
    map.set(id, value);
}
// 2. remove duplicates
for (let value of aList) {
    const id3 = `${value.division} / ${value.branch} / ${value.department}`;
    if (map.get(id3) != value) map.delete(id3);
    const id2 = `${value.division} / ${value.branch} / ${undefined}`;
    if (map.get(id2) != value) map.delete(id2);
    const id1 = `${value.division} / ${undefined} / ${undefined}`;
    if (map.get(id1) != value) map.delete(id1);
}
const result = Array.from(map.values());
console.log(result)

Comments

1

I am assuming by most detailed you mean the object containing the most properties, hence being the most detailed object?

In that case you could possible count the amount of keys in the object, and only grab the object with the most keys, hence grabbing the most detailed object.

EDIT: If the objects will always have at least the division key value, you could execute these steps:

  1. First look for objects that share the same key value for division. If there are no matches, it's unique and the most detailed already.
  2. Extract the object that has the most key/value pairs in the object. So { division: "val1", key2: "val2"} gets returned, and { division: "val1" } does not.

You should end up with objects that have unique division values, and are the most detailed objects.

1 Comment

Thanks, but note that it should also be unique with the data inside, not just number of objects

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.