1

Suppose you have a class Table which contains the attribute: records (list of dictionaries) and keys which is the primary key of each table (just like SQL) - Tuple

I need to write a lambda function that takes a new row and then spit out True or False if all the values of the keys in the new row are already in the table

For example:

# Table: orders

keys = ('product_id', 'customer_id')

records: [{'product_id': 51, 'customer_id' : 10, 'units':9},
          {'product_id': 32, 'customer_id' : 11, 'units':33},
          {'product_id': 39, 'customer_id' : 47, 'units':2}]

and now the new row we want to check is:

{'product_id': 51, 'customer_id' : 10, 'units': 77 }

This would return True because product_id==51 and customer_id==10 just like the first dictionary in the record (the units does not matter, because its not a key).

However this:

{'product_id': 51, 'customer_id' : 11, 'units':9}

Will return False because there is no row with product_id==51 and customer_id==11

We must use lambda functions (we don't have to use filter, just a hint)
I've tried many many different ways of 'attacking' this question, but I couldn't iterate over a list of keys and a tuple at the same time...

contains_key = lambda self, new_row: list(filter(  
  (lambda con: con[self.__key]), 
  [record for record in self.__records] 
))

Explanation: self is the table we do the operation on, new_row is the row (dictionary) to check
self.__keys is the tuple of keys (like primary keys in sql) and self.__records is the list of dictionaries="""rows in an sql table""")
The function is inside the class Table (that's why it's in the "self" form)

class Table:
    def __init__(self, key_set):
        self.__key = tuple(key_set)
        self.__records = []

    def add_record(self, new_record):
        self.__records.append(new_record)
12
  • 1
    "need to write a lambda function " - Why? Commented Jan 10, 2020 at 1:07
  • 1
    doing x = lambda ... kinda loses the point of lambdas... Commented Jan 10, 2020 at 1:07
  • @HeapOverflow It's a university task. I have no idea why would you use lambdas is such an awful way, and they actually said it in the task (it's just to explain how to write it) Commented Jan 10, 2020 at 1:09
  • I'm assuming this is some kind of assignment for a CS or programming class and this is why you're trying to write this as a lambda. This is actually an anti-pattern in normal Python programming, you shouldn't assign a lambda to a name, in that case a def is almost always better. Commented Jan 10, 2020 at 1:09
  • @Grismar Correct sir. :) Commented Jan 10, 2020 at 1:10

3 Answers 3

2

A simple use of any and all will do the trick: "check if all keys of any record are the same as the new record":

print(any(all(new_record[key] == record[key] for key in keys) for record in records))

The good thing with those functions is short-circuiting: whenever a key doesn't match - the record will be skipped, and when a record is matched - no more records will be checked.


I will leave it to you as an exercise to turn that into a lambda :)

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

2 Comments

Hi, If there is a dictionary in the orders like so: order3 = {'customer_id' : '13','product_id' : '1234-5', 'units': 9 } and we test it with another dictionary: order4 = {'customer_id': '13', 'product_id':'1234-5', 'units':3} The final answer is "False" and should be True, I have no idea why it looks OK to me though.
Wait, my bad. it works totally fine. Thank you very much and when I read this function I now understand clearly the pattern. many many thanks!
0

Something like this, it seems:

class Table:
    def __init__(self, key):
        # using the __ in an odd way
        self.__key = key
        self.__records = []

    # only using lambda because you must, it's pointless
    contains_key = lambda self, record: any(all(record[f] == r[f] for f in self.__key) for r in self.__records)

    def add(self, record):
        if not self.contains_key(record):
            self.__records.append(record)
        else:
            raise Exception('duplicate key')


t = Table(('product_id', 'customer_id'))
t.add({'product_id': 51, 'customer_id': 10, 'units': 9})
t.add({'product_id': 32, 'customer_id': 11, 'units': 33})
t.add({'product_id': 39, 'customer_id': 47, 'units': 2})
# fails
t.add({'product_id': 39, 'customer_id': 47, 'units': 2})

But if this is what they're teaching you, I'd look for a better class.

If I replace:

# fails
t.add({'product_id': 39, 'customer_id': 47, 'units': 2})

With

t.add({'customer_id': '13', 'product_id': '1234-5', 'units': 9})
print(t.contains_key({'customer_id': '13', 'product_id': '1234-5', 'units': 3}))

The result is True.

3 Comments

Hi, if i have a dictionary: {'customer_id' : '13','product_id' : '1234-5', 'units': 9 } and try to do it with : {'customer_id': '13', 'product_id':'1234-5', 'units':3} it returns false, but it should return true as customerid 13 and product id 1234-5 is already in the table
Not sure what you're doing wrong, but see the edit in the answer.
Wait, my bad. it works totally fine. Thank you very much and when I read this function I now understand clearly the pattern. many many thanks!
0

Here's a canonical answer to start with:

def has_row(records, keys, row):
    return any(
        all(row[k] == x[k] for k in keys)
        for x in records
    )

The conversion to a "lambda function" is trivial:

has_row = (lambda records, keys, row:
    any(
        all(row[k] == x[k] for k in keys)
        for x in records
    )
)

If you're not "allowed" to use any or all, they can be replaced as follows:

any = (lambda xs:
    bool(next(filter(lambda x: x, xs), False))
)

# Alternatively, without using next:
any = (lambda xs:
    len(list(filter(lambda x: x, xs))) != 0
)

all = (lambda xs:
    len(list(filter(lambda x: not x, xs))) == 0
)

3 Comments

@HeapOverflow Whoops can't believe I ordered those wrong after writing some Haskell recently...
@HeapOverflow You mean like filter(None, xs)? Neat trick to remember, but I'll leave it like this for the OP who's already a bit confused. ;)
Yes, I meant None. Another idea: all = lambda xs: min(map(bool, xs), default=True) and any = lambda xs: max(map(bool, xs), default=False).

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.