Skip to content
Advertisement

How to filter out object items with unique values in an array in JavaScript

I am trying to filter out countries in an array of objects with unique currency. The country array structure is

[
    {
        country: "A",
        currencies: [{code: "USD"}, {code: "EURO"}]
    },
    {
        country: "B",
        currencies: [{code: "AFN"}]
    },
    {
        country: "C",
        currencies: [{code: "CND"}, {code: "EURO"}]
    },
    {
        country: "D",
        currencies: [{code: "USD"}]
    }
]

What I’m trying to achieve is to filter the country array such that the output array contains only countries with unique value like

[
    {
        country: "B",
        currencies: [{code: "AFN"}]
    },
    {
        country: "C",
        currencies: [{code: "CND"}, {code: "EURO"}]
    }
]

The countries A and D have both non-unique currency values. In case of country C, even though EURO is non unique, it’s other currency code CND is an unique value. I had used array filter method but couldn’t find a solution. Any help is appreciated.

Advertisement

Answer

You could get an object of grouped objects by code, get only the arrays with a single item, flat the result and get only unique objects as result.

const
    data = [{ country: "A", currencies: [{ code: "USD" }, { code: "EURO" }] }, { country: "B", currencies: [{ code: "AFN" }] }, { country: "C", currencies: [{ code: "CND" }, { code: "xEURO" }, { code: "EURO" }] }, { country: "D", currencies: [{ code: "USD" }] }],
    result = Object
        .values(data.reduce((r, o) => {
            o.currencies.forEach(({ code }) => (r[code] ??= []).push(o));
            return r;
        }, {}))
        .filter(a => a.length === 1)
        .flat()
        .filter((s => o => !s.has(o) && s.add(o))(new Set));

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

A slightly shorter approach

You could get an object of grouped objects by code, with either the index or false, take the values as indices array and filter the data by having a look to the indices array.

const
    data = [{ country: "A", currencies: [{ code: "USD" }, { code: "EURO" }] }, { country: "B", currencies: [{ code: "AFN" }] }, { country: "C", currencies: [{ code: "CND" }, { code: "xEURO" }, { code: "EURO" }] }, { country: "D", currencies: [{ code: "USD" }] }],
    indices = Object.values(data.reduce((r, o, i) => {
        o.currencies.forEach(({ code }) => r[code] = !(code in r) && i);
        return r;
    }, {})),
    result = data.filter((_, i) => indices.includes(i));

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