LNA
LNA

Reputation: 1447

Transform a list of lists into another format

I have a list of lists that looks like this:

names_list = [
["first='Katie'", "last='Beckett'"], 
["first='David'", "last='Seal'"],
["first='Eric'", "last='Swartz'"]
]

I want to transform it into this format:

object.filter(first='Katie', last="Beckett') | object.filter(first='David', last='Seal' | object.filter(first='Eric', last="Swartz')

This is what I've been trying:

def convert(list):
    for i in list:
        return reduce(lambda x,y: objects.filter + '(' + x + ', ' + y + ')' , i)

map(lambda i: convert(i), names_list ))

Upvotes: 0

Views: 76

Answers (1)

bruno desthuilliers
bruno desthuilliers

Reputation: 77912

The "programming by accident" approach (ie trying anything aphazardly without the slightest understanding and hoping it will magically "kind of work") won't take you very far. You need to understand what you're doing and why.

First point: your target is a Python expression, not data, so what you want is not to "transform" your source data "into another format" but to dynamically build (and eval) the expression from your source data.

Second point: your source data format is just plain wrong, you don't want litteral "first=<...>" strings here but very obviously a list of dicts ie:

names_list = [
    {"first":'Katie', "last":'Beckett'}, 
    {"first":'David', "last":'Seal'},
    {"first":'Eric', "last":'Swartz'}
    ]

This allow you to use dict unpacking in a function call, ie:

 target = names_list[0]
 result = object.filter(**target)

Third point: objects.filter + '(' + x + ', ' + y + ')' doesn't mean anything - trying to add a function and a string just won't work. Don't try to build Python expressions as string anyway, Python is expressive and dynamic enough to let you solve those kind of problems without such dirty hacks.

What you want here is to 1. build a sequence of calls (well results of the calls that is) to object.filter() then 2. "or" these results together.

The first step is quite easy:

items = [object.filter(**target) for target in names_list]

The second step is to "reduce" this sequence using the "biwise or" operator (|). reduce() is indeed the right function for this, you just need a function taking two of your items and "or'ing" them. The naive approach is to use a lambda:

result = reduce(lambda y, x: x | y, items)

but this is a case of reinventing the wheel since Python's operators (well, most of them) exist in a function version in the operator module:

import operator
result = reduce(operator.or_, items)

Upvotes: 2

Related Questions