Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Find object in collection with fuzzy matching

I have a collection that looks something like this:

const collection = [
    {
        name: 'THIS_ITEM',
        conditions: {
            oneCondition: false,
            anotherCondition: false,
            yourCondition: false,
            myCondition: false
        }
    }, {
        name: 'THAT_ITEM',
        conditions: {
            oneCondition: false,
            anotherCondition: false,
            yourCondition: true,
            myCondition: false
        }
    }, {
        name: 'THOSE_ITEMS',
        conditions: {
            oneCondition: true,
            anotherCondition: false,
            yourCondition: null,
            myCondition: false
        }
    }
];

… and later an object that looks like this:

const condition = {
    oneCondition: true,
    anotherCondition: false,
    yourCondition: true,
    myCondition: false
};

I’m trying to match the condition object against the nested conditions objects in collection to find the one that matches so I can retrieve the name property from the matching entry.

The thing that’s throwing me for a loop is the fact that the conditions properties can have “fuzzy” values. By that I mean that if any properties in the source collection are set to true or false they MUST match the values in condition exactly. But if the property in the source collection has a value of null it can match either true or false.

Example:

These would match:

const condition = {
    oneCondition: true,
    anotherCondition: false,
    yourCondition: true,
    myCondition: false
};

const collection = [
    …
    }, {
        name: 'THOSE_ITEMS',
        conditions: {
            oneCondition: true,
            anotherCondition: false,
            yourCondition: null,
            myCondition: false
        }
    }
];

These would not:

const condition = {
    oneCondition: true,
    anotherCondition: false,
    yourCondition: true,
    myCondition: false
};

const collection = [
    …
    }, {
        name: 'THAT_ITEM',
        conditions: {
            oneCondition: false,
            anotherCondition: false,
            yourCondition: true,
            myCondition: false
        }
    }, {
    …
];

Any suggestions? I’m using Lodash but can’t seem to imagine any solution without an overly-verbose and nested concoction.

like image 492
Brandon Durham Avatar asked Oct 18 '22 12:10

Brandon Durham


2 Answers

You could use Array#filter with Array#every for the conditions and test against null value as wildcard.

var collection = [{ name: 'THIS_ITEM', conditions: { oneCondition: false, anotherCondition: false, yourCondition: false, myCondition: false } }, { name: 'THAT_ITEM', conditions: { oneCondition: false, anotherCondition: false, yourCondition: true, myCondition: false } }, { name: 'THOSE_ITEMS', conditions: { oneCondition: true, anotherCondition: false, yourCondition: null, myCondition: false } }],
    condition = { oneCondition: true, anotherCondition: false, yourCondition: true, myCondition: false },
    result = collection.filter(o =>
        Object.keys(condition).every(k =>
            o.conditions[k] === null || o.conditions[k] === condition[k]
        )
    );

console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
like image 130
Nina Scholz Avatar answered Oct 21 '22 00:10

Nina Scholz


You can use lodash#filter with lodash#isMatch and lodash#omitBy to match the condition against a collection object's condition that doesn't contain any null values.

const result = _.filter(collection, v => 
  _.isMatch(condition, _.omitBy(v.conditions, _.isNull))
);

const collection = [
    {
        name: 'THIS_ITEM',
        conditions: {
            oneCondition: false,
            anotherCondition: false,
            yourCondition: false,
            myCondition: false
        }
    }, {
        name: 'THAT_ITEM',
        conditions: {
            oneCondition: false,
            anotherCondition: false,
            yourCondition: true,
            myCondition: false
        }
    }, {
        name: 'THOSE_ITEMS',
        conditions: {
            oneCondition: true,
            anotherCondition: false,
            yourCondition: null,
            myCondition: false
        }
    }
];

const condition = {
    oneCondition: true,
    anotherCondition: false,
    yourCondition: true,
    myCondition: false
};

const result = _.filter(collection, v => 
  _.isMatch(condition, _.omitBy(v.conditions, _.isNull))
);


console.log(result);
body > div { min-height: 100%; top: 0; }
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.4/lodash.js"></script>
like image 21
ryeballar Avatar answered Oct 20 '22 22:10

ryeballar