3

Question related to this post.

I need help to filter a list of lists depending on a variable set of conditions.

Here is an extract of the list:

ex = [
    # ["ref", "type", "date"]
    [1, 'CB', '2017-12-11'],
    [2, 'CB', '2017-12-01'],
    [3, 'RET', '2017-11-08'],
    [1, 'CB', '2017-11-08'],
    [5, 'RET', '2017-10-10'],
]

I want to apply a final treatment like list(filter(makeCondition, ex)) where makeCondition(myList, **kwargs) function returns a boolean that enables to filter the list.

I have troubles building this function as adviced in this post, as the number of conditions defined in the **kwargs dictionnary is variable.

Examples of conditions sets:

conditions = {"ref": 3}
conditions = {"ref": 1, "type": "CB"}

Here is a start:

def makeConditions(myList, **p):

    # For each key:value in the dictionnary
    for key, value in p.items():

        if key == "ref":
            lambda x: x[0] == value
        elif key == "type":
            lambda x: x[1] == value
        elif key == "date":
            lambda x: x[2] == value

    # return chained conditions...

list(filter(makeConditions, ex))

I don't get the logical idea that various comments attempted to give in the post mentioned above... Do I have to execute the filter() function for each sublist or is it possible to do it for the whole global list? Any advices will be very welcome!

2
  • will it have always ref, type and date, or is it variable? Commented Dec 12, 2017 at 10:04
  • The conditions variable is variable indeed, as shown in the post. The content of the sublists is always constant with the 3 objects: ref, type and date. Commented Dec 12, 2017 at 10:07

2 Answers 2

2

I would simply make a function that returns the conditional:

def makeConditions(**p):
    fieldname = {"ref": 0, "type": 1, "date": 2 }
    def filterfunc(elt):
        for k, v in p.items():
            if elt[fieldname[k]] != v: # if one condition is not met: false
                return False
        return True
    return filterfunc

Then you can use it that way:

>>> list(filter(makeConditions(ref=1), ex))
[[1, 'CB', '2017-12-11'], [1, 'CB', '2017-11-08']]
>>> list(filter(makeConditions(type='CB'), ex))
[[1, 'CB', '2017-12-11'], [2, 'CB', '2017-12-01'], [1, 'CB', '2017-11-08']]
>>> list(filter(makeConditions(type='CB', ref=2), ex))
[[2, 'CB', '2017-12-01']]
Sign up to request clarification or add additional context in comments.

1 Comment

It looks good and so much shorter... Thanks @Serge Ballesta! I'll have a closer look to it and come back.
0

You was almost there, the idea is to create a list with the functions that checks the conditions you need, once you have them you can just call those functions over the list they have to check and use all function to check if all of them are evaluated to True, note the use of partial so the function in the filter call only takes the data list; check this:

from functools import partial

ex = [
    # ["ref", "type", "date"]
    [1, 'CB', '2017-12-11'],
    [2, 'CB', '2017-12-01'],
    [3, 'RET', '2017-11-08'],
    [1, 'CB', '2017-11-08'],
    [5, 'RET', '2017-10-10'],
]

conditions  = {"ref": 3}
conditions2 = {"ref": 1, "type": "CB"}

def apply(data, *args):
"""
same as map, but takes some data and a variable list of functions instead
it will make all that functions evaluate over that data
"""
  return map(lambda f: f(data), args)


def makeConditions(p, myList):
    # For each key:value in the dictionnary
    def checkvalue(index, val, lst):
      return lst[index] == val
    conds = []
    for key, value in p.items():
        if key == "ref":
            conds.append(partial(checkvalue, 0, value))
        elif key == "type":
            conds.append(partial(checkvalue, 1, value))
        elif key == "date":
            conds.append(partial(checkvalue, 2, value))
    return all(apply(myList, *conds)) # does all the value checks evaluate to true?

#use partial to bind the conditions to the makeConditions function
print(list(filter(partial(makeConditions, conditions), ex)))
#[[3, 'RET', '2017-11-08']]
print(list(filter(partial(makeConditions, conditions2), ex)))
#[[1, 'CB', '2017-12-11'], [1, 'CB', '2017-11-08']]

Here you have a live example

Do I have to execute the filter() function for each sublist or is it possible to do it for the whole global list?

Filter iterates over all the list aplying a function for each of the elements, if the function evaluates to True then the element will remind in the result, so filter works over the whole global list

2 Comments

Many thanks @Daniel Sanchez! Several new things to me in your suggestion, anyway it works very well. I have to read the doc about partial() function. I don't get how the checkvalue() function finds the index argument.
@wiltomap, partial binds values to functions arguments returning another function with those arguments fixed with those values, so when i call partial(checkvalue, 0, value) im creating a function that will do the same as your lambdas, just to be used afterwards.

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.