3

I have a list of all available stock items with a unique stock id and detail attributes. From the UI, I collect customer selection, based on the unique value code in customer selection, I would like to find the selected item from the stock items. That is,

What is the best approach to find stockItem from availableStock that matches the value code attribute in customerSelection array list? Please have a look at the example below:

const customerSelection = {
    "tv": [
        {
            "value": "tv_40",
            "label": "Flat Screen"
        }
    ],
    "keyboard": [
        {
            "value": "keyboard_40",
            "label": "Wireless Keyboard"
        }
    ],
    "mouse": [
        {
            "value": "mouse_40",
            "label": "Wireless Mouse"
        }
    ]
};
const availableStock = [
    {
        "stockId": "elec_c1_f1",
        "attributes": [
            {
                "label": "Flat Screen",
                "value": "tv_41"
            },
            {
                "label": "Wireless Keyboard",
                "value": "keyboard_41"
            },
            {
                "label": "Wireless Mouse",
                "value": "mouse_41"
            }
        ]
    },
    {
        "stockId": "elec_c1_f2",
        "attributes": [
            {
                "label": "Flat Screen",
                "value": "tv_40"
            },
            {
                "label": "Wireless Keyboard",
                "value": "keyboard_40"
            },
            {
                "label": "Wireless Mouse",
                "value": "mouse_40"
            }
        ]
    },
    {
        "stockId": "elec_c1_f3",
        "attributes": [
            {
                "label": "Flat Screen",
                "value": "tv_42"
            },
            {
                "label": "Wireless Keyboard",
                "value": "keyboard_42"
            },
            {
                "label": "Wireless Mouse",
                "value": "mouse_42"
            }
        ]
    }
]

Expected result with stockId (or Just the stockId)

const stockItem = {
    "stockId": "elec_c1_f2",
    "attributes": [
        {
            "label": "Flat Screen",
            "value": "tv_40"
        },
        {
            "label": "Wireless Keyboard",
            "value": "keyboard_40"
        },
        {
            "label": "Wireless Mouse",
            "value": "mouse_40"
        }
    ]
}

Any suggestion with/without lodash is appreciated.

3 Answers 3

2

I'd suggest creating a requiredValues array, using Array.values() and Array.map().

This will look like:

[ "tv_40", "keyboard_40", "mouse_40" ]

We'd then use Array.filter() to find all stock items with every required value present in its attributes.

We'd use Array.every(), along with Array.find() to ensure every required value is present in the item attributes.

This would return a list of the stock items.

We can then map to get a list of matching stock ids:

const customerSelection = { "tv": [ { "value": "tv_40", "label": "Flat Screen" } ], "keyboard": [ { "value": "keyboard_40", "label": "Wireless Keyboard" } ], "mouse": [ { "value": "mouse_40", "label": "Wireless Mouse" } ] };

const availableStock = [ { "stockId": "elec_c1_f1", "attributes": [ { "label": "Flat Screen", "value": "tv_41" }, { "label": "Wireless Keyboard", "value": "keyboard_41" }, { "label": "Wireless Mouse", "value": "mouse_41" } ] }, { "stockId": "elec_c1_f2", "attributes": [ { "label": "Flat Screen", "value": "tv_40" }, { "label": "Wireless Keyboard", "value": "keyboard_40" }, { "label": "Wireless Mouse", "value": "mouse_40" } ] }, { "stockId": "elec_c1_f3", "attributes": [ { "label": "Flat Screen", "value": "tv_42" }, { "label": "Wireless Keyboard", "value": "keyboard_42" }, { "label": "Wireless Mouse", "value": "mouse_42" } ] } ]
    
// These values must be present in the attributes...
const requiredValues = Object.values(customerSelection).map(val => val[0].value);

// Use Array.filter() to find stock items that match _all_ required attributes...
const foundItems = availableStock.filter(item => {
    return requiredValues.every(value => item.attributes.find(attr => attr.value === value));
});

console.log('Found stockIds:', foundItems.map(({ stockId }) => stockId));
console.log('Found items:', foundItems);
.as-console-wrapper { max-height: 100% !important; top: 0; }

You could also do this without building the requiredValues array first and simply call .every() on the customerSelection array:

const customerSelection = { "tv": [ { "value": "tv_40", "label": "Flat Screen" } ], "keyboard": [ { "value": "keyboard_40", "label": "Wireless Keyboard" } ], "mouse": [ { "value": "mouse_40", "label": "Wireless Mouse" } ] };
const availableStock = [ { "stockId": "elec_c1_f1", "attributes": [ { "label": "Flat Screen", "value": "tv_41" }, { "label": "Wireless Keyboard", "value": "keyboard_41" }, { "label": "Wireless Mouse", "value": "mouse_41" } ] }, { "stockId": "elec_c1_f2", "attributes": [ { "label": "Flat Screen", "value": "tv_40" }, { "label": "Wireless Keyboard", "value": "keyboard_40" }, { "label": "Wireless Mouse", "value": "mouse_40" } ] }, { "stockId": "elec_c1_f3", "attributes": [ { "label": "Flat Screen", "value": "tv_42" }, { "label": "Wireless Keyboard", "value": "keyboard_42" }, { "label": "Wireless Mouse", "value": "mouse_42" } ] } ]

const foundItems = availableStock.filter(item => {
    return Object.values(customerSelection).every(([{ value }]) => { 
        return item.attributes.find(attr => attr.value === value);
    });
});

console.log('Found stockIds:', foundItems.map(({ stockId }) => stockId));
console.log('Found items:', foundItems);
.as-console-wrapper { max-height: 100% !important; top: 0; }

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

Comments

1

Firstly get all keys from customer selection:

var values = Object.keys(customerSelection).map(element =>customerSelection[element][0].value)

Then get matchedAvailableValues by using this code:

var matchedAvailableValues = availableStock.filter(element => values.includes(element.attributes[0].value) ? {stockId:element.stockId,attributes:element.attributes} : false);

So your final code looks like this:

var values = Object.keys(customerSelection).map(element => customerSelection[element][0].value)
var matchedValues = availableStock.filter(element => values.includes(element.attributes[0].value) ? {stockId:element.stockId,attributes:element.attributes}:false);

5 Comments

thanks @onurkan Bakrirci, your suggestion results: ``` [ { stockId: 'elec_c1_f2', attributes: [ [Object], [Object], [Object] ] } ] ``` which is close to what I wanted to achieve, would it be possible to extract the only object with all details of the attributes field? for now, I see Object
If you use console.log() for see result, result will shown as an Object. You can see actual result by console.log(matchedValues[0])
I just noticed this solution returns multiple stock items if they partially matched with attributes in customer selection.
I can't clearly understand the problem. Can you give more information about problem?
If you add one more object to availableStock list and re-run the code, you will understand what I mean. { "stockId": "elec_c1_f4", "attributes": [ { "label": "Flat Screen", "value": "tv_42" }, { "label": "Wireless Keyboard", "value": "keyboard_11" }, { "label": "Wireless Mouse", "value": "mouse_42" } ] }
0

Use nested for..in loops to navigate both objects.

const customerSelection = {
    "tv": [
        {
            "value": "tv_41",
            "label": "Flat Screen"
        }
    ],
    "keyboard": [
        {
            "value": "keyboard_40",
            "label": "Wireless Keyboard"
        }
    ],
    "mouse": [
        {
            "value": "mouse_40",
            "label": "Wireless Mouse"
        }
    ]
};
const availableStock = [
    {
        "stockId": "elec_c1_f1",
        "attributes": [
            {
                "label": "Flat Screen",
                "value": "tv_41"
            },
            {
                "label": "Wireless Keyboard",
                "value": "keyboard_41"
            },
            {
                "label": "Wireless Mouse",
                "value": "mouse_41"
            }
        ]
    },
    {
        "stockId": "elec_c1_f2",
        "attributes": [
            {
                "label": "Flat Screen",
                "value": "tv_40"
            },
            {
                "label": "Wireless Keyboard",
                "value": "keyboard_40"
            },
            {
                "label": "Wireless Mouse",
                "value": "mouse_40"
            }
        ]
    },
    {
        "stockId": "elec_c1_f3",
        "attributes": [
            {
                "label": "Flat Screen",
                "value": "tv_42"
            },
            {
                "label": "Wireless Keyboard",
                "value": "keyboard_42"
            },
            {
                "label": "Wireless Mouse",
                "value": "mouse_42"
            }
        ]
    }
];

for (o in customerSelection)
for (p in availableStock)
for (q in availableStock[p].attributes) 
if (customerSelection[o][0].value==availableStock[p].attributes[q].value) console.log(availableStock[p].stockId);

2 Comments

Thanks @JMP, the code you suggested returns stockIds, elec_c1_f1, elec_c1_f2, & elec_c1_f2. But I was expecting only elec_c1_f2.
I changed the first item in customerSelection because my code returns a stockId for each item in customerSelection rather than assume they are all going to be in the same stock group.

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.