0

thank you for help. I have an array of objects. And i can't find good solution except of a lot of IF's how to filter it depends on array of properties that should be checked.

const offers = [
  {
    isGrouped: true,
    isDiscarded: false,
    isCopy: false,
    isWarned: false,
    name: "qw",
  },
  {
    isGrouped: false,
    isDiscarded: true,
    isCopy: false,
    isWarned: false,
    name: "qwer",
  },
  {
    isGrouped: false,
    isDiscarded: true,
    isCopy: true,
    isWarned: false,
    name: "erw",
  },
  {
    isGrouped: false,
    isDiscarded: false,
    isCopy: true,
    isWarned: false,
    name: "frew",
  }]

and here is the array of filters

export enum Status {
  DISCARDED = "Discarded",
  WARNED = "Warning",
  COPY = "Copy",
  GROUPED = "Grouped",
}

const filters: string[] = [Status.DISCARDED, Status.COPY];

filters could include all four statuses or one, two, three or any of them.

function check(offer, filters) {
    // I don't know actually how to handle filtering here.
    // only one idea is to check all possible variants ex.
    
    // if (filters.includes(Status.DISCARDED) && filters.length === 1) {
    //     return offer.isDiscarded
    // } else if (filters.includes(Status.DISCARDED) && filters.includes(Status.COPY) && filters.length === 2) {
    //     return offer.isDiscarded || offer.isCopy
    // }
}

offers.filter(offer => check(offer, filters))

My solutuion doesn't looks nice. Could someone take a look please?

2 Answers 2

2
type Offer = { [K in Status as `is${K}`]?: boolean }

function check(offer: Offer, filterStatus: Status[]): boolean {
    for (const status of filterStatus) {
        const propertyName = "is"+status as `is${typeof status}`
        if (!offer[propertyName]) return false
    }
    return true
}
Sign up to request clarification or add additional context in comments.

4 Comments

problem is that properties in object can't be changed and enum Status also can't be changed
@RomanChygryn what do you mean? If I use this answer and your code it seems to work okay with the exception that you should not intentionally widen filters from Status[] to string[]. If you have a problem with this answer could you elaborate on exactly where the problem is?
@jcalz I edited my code after his comment. Should i have said so in a comment ? Sorry for the confusion.
@Jean-Alphonse: Yes, if you change the answer in a way that invalidates a comment, it's customary to note it in a responding comment. (Then it might get confusing if the commenter subsequently deletes that comment, but it seems the best process.)
0

I would layer this atop a more general-purpose function that tests whether a collection of key/value pairs matches your object. We can layer on something which maps Discarded to isDiscarded, etc.

const checkProps = (entries) => (x) =>
  entries .every (([k, v]) => x [k] == v)

const check = (filters) => 
  checkProps (filters .map (k => [`is${k}`, true]))

const findMatches = (offers, filters) =>
  offers .filter (check (filters))


const offers = [{isGrouped: true, isDiscarded: false, isCopy: false, isWarned: false, name: "qw"}, {isGrouped: false, isDiscarded: true, isCopy: false, isWarned: false, name: "qwer",}, {isGrouped: false, isDiscarded: true, isCopy: true, isWarned: false, name: "erw", }, {isGrouped: false, isDiscarded: false, isCopy: true, isWarned: false, name: "frew"}]
const Status = {DISCARDED: "Discarded", WARNED: "Warning", COPY: "Copy", GROUPED: "Grouped"}


console .log (findMatches (offers, [Status.DISCARDED, Status.COPY]))

checkProps takes an array of key-value pairs and returns a function which accepts an object, reporting whether all those keys in the object match the relevant value. check takes your filters and turns them into such an array of key-value pairs by prepending "is" to the filter name and pairing it up with the value true. We could use this by directly calling

offers .filter (check (filters))

but I find it cleaner to wrap that in the function findMatches

This offers a fairly flexible API, but we can probably get even more flexible without making it much harder to use. Imagine this:

students .filter (where ({
  gpa: gte (3.0),
  grade: eq (11),
  gender: eq ('male'),
  demerits: lt (3)
}))

It would be relatively easy to build an API that worked like that on very similar principles to the above, and it would be straightforward to layer your function on top of this. I wont try to write it here. But this is a demonstration of a useful point: it often helps simplify your code to think of it more generically and then add your special case on top of the generic abstraction.

Comments

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.