Error return function

return list(
    map(
        lambda v: {
            "open_time": float(v[0]),
            "open": float(v[1]),
            "high": float(v[2]),
            "low": float(v[3]),
            "close": float(v[4]),
        }
    )
)

Buenos dias, estoy teniendo problemas para retornar a la lista, alguno tiene idea de a que se debe? gracias

First, for some basic theory.

  1. map accepts two arguments. Here, you have given only one argument; the lambda
    anonymous function.

  2. Lambda may accept multiple arguments and may return only one expression. Here, it appears as if you are attempting to do it backwards. You are giving it one argument ( a list counts as one argument here), and attempting to return multiple expressions, as noted by the commas.

I donā€™t believe that the lambda anonymous function can return what you want it to, as it is currently written.

You can get your expected result by making use of the zip built-in function along with the dict built-in function.

keys = ['open_time', 'open', 'high', 'low', 'close']
values = [3.1,4.18,5.05,6.45,7.02]

def abc(a, b):
    return dict(zip(keys,values))

pairs = abc(keys, values)
print(pairs)
print(pairs['open'])

Theoretically, the lambda is fine: it takes an argument and returns a dictionary with 5 named entries. Its argument would have to be some kind sequence (tuple, list) with at least 5 elements.

The call to map, however, does need a second argument, which would have to be a list (ok, any iterable) where the elements are these 5-tuples. The code would then produce a list of dictionaries with 5 elements each. It seems unlikely this is the OPā€™s intent.

Not sure about this. I failed to guess what the intended result was. :man_shrugging:

From the arguments that were provided by @IvanKo in the expression, it appears that he was attempting to create a dictionary by way of the curly brackets and strings as the keys, and the list indexes as the values.

If I was wrong in my assumption, I am sure he can further clarify in subsequent post.

Another thing that I forgot to mention, the code also appears to want to use a return statement without it being within a function which you canā€™t do.

Right, but thatā€™s what the lambda already does (correctly, as Jeff mentions). ISTM that the point @jeff5 was making is that it isnā€™t easily possible to reliably guess as to what the OP wanted to do beyond that, given the OPā€™s code is missing the second argument to map, it isnā€™t obvious how or why they want to transform the resulting dict to a list, and the only minimal context they provided is that they have unspecified ā€œproblemsā€ returning the list, which gives essentially no helpful clues as to their intent.

One guess is that they are trying to transform a list into a dict, and then back into a list, but wrt to the second transformation there is nothing to indicate how or why they would logically want to do this, or what actual purpose this snippet of code is intended to serve.

@IvanKo , any help here?

Or whether. I donā€™t think they do. Looks like they want to transform the map iterator to a list, i.e., create a list of dicts. Only thing missing is the data source, as second argument for map.

Ah, yeahā€”that makes a lot more sense; they have some sequence of sequences (say, lst) that they want to pass to map in order to use their lambda to transform them into a list of dicts. In that case, they could replace their current functional-style logic by a more concise and Pythonic comprehension:

fields = ["open_time", "open", "high", "low", "close"]
return [{k: float(v) for k, v in zip(fields, data)} for data in lst]

EDIT: Or a hybrid approach per @Stefan2 's comment:

fields = ["open_time", "open", "high", "low", "close"]
return [dict(zip(fields, map(float, data))) for data in lst]

Just add lst.

Or dict(zip(fields, map(float, data))).

(And ooh, now itā€™s tempting to rewrite your whole solution as an itertools contraption without any Python-level loopingā€¦ Iā€™m just not in the mood to write testing data/codeā€¦)

1 Like

Ah well, the urge was too strong:

from itertools import repeat

list(map(dict, map(zip, repeat(fields), map(map, repeat(float), lst))))

Attempt This Online!

1 Like

Hi, just following up here. Retested the code. You are correct. It works fine. I did a mistake regarding how I had entered the inputs when testing the lambda anonymous function.
I tried executing his code as is and it does ā€˜workā€™ (I added an arbitrary list to serve as a valid reference):

v = [1,2,3,4,5]

result = lambda v: {
            "open_time": float(v[0]),
            "open": float(v[1]),
            "high": float(v[2]),
            "low": float(v[3]),
            "close": float(v[4]),}

print(result([7,6,5,4,3]))  # Works this way

#print(result(7,6,5,4,3)) # Does not work - how I had originally tested it

I am used to making use of a more ā€˜standardā€™ lambda anonymous functions. For example:

use = lambda x : x ** 2
print(use(2))

Notice how the input is within the two parenthesis. This is how I had originally tested the lambda expression above and thus why it did not work.

It isnā€™t entirely made explicit how this ā€œstandardā€ use of lambda is different from the previous, but I surmise you may be referring to its definition only occupying a single physical line, which indeed is the primary intended use-case of lambdas in Python.

Of course, just to be clear, immediately assigning a lambda anonymous function to a name is quite-non-ā€œstandardā€, as that defeats the purpose of the function being anonymous in the first place. A much more ā€œstandardā€ example or test would be passing a lambda to a functional construct, like map as used in the OPā€™s original example, e.g.

list(map(lambda x: x**2, [1, 2, 3]))

To be fair, in both cases the argument to the (not-so-anonymous) function is ā€œwithin two parenthesisā€; the error was simply passing the numbers as separate arguments rather than a single list, as the function expected and the error message states:

TypeError: () takes 1 positional argument but 5 were given

Perhaps you were confused by <lambda>() instead of a function name, but this is a great example of why one should use a normal named function instead of an anonymous one if youā€™re just going to assign it to a name anyway.

1 Like

Yes, I understand this. From using tkinter, this is usually the way that they are used for the command argument - anonymously. But, here, this was just for test purposes so that you can immediately test the results via the print statement.

Another issue that I also found a bit confusing with regard to how the issue was defined is that the expression required a pre-defined list in order to set up their lambda function. In other, more simpler expressions, and how textbooks generally explain/define them, the expression is void of any initial values. Here, it appears that it is required in order to set it up, ā€¦, since you canā€™t reference un-assigned list index values.

Right, though I suggest you test the lambda as closely as possible to how it would actually be used, to avoid these sorts of mistakes that are easy for anyone to make otherwise; as demonstrated by my example, using it in map() as in the original OP was actually shorter than giving it a name and calling it as a non-anonymous function, and more representative of the actual problem the OP was facing.

Iā€™m not sure what you mean by ā€œpre-defined listā€ and ā€œset upā€ here, sorry. Most useful lambdas take one or more arguments, which themselves may be collections or any arbitrary object. And Iā€™m not sure what ā€œset upā€ youā€™re referring to; in all cases a lambda in Python can only be a single expression, and thereā€™s no ā€œset upā€ code for this lambda.

Well, here, as an example, I have two lambda functions. I do not need an external list, or any other external object in order to define it.

command = lambda x: x ** 2 + 5*x +10

command  = lambda y, z: 10*y*z -(5/6)*z + 4.5*y

The way that they had defined it, you need an external list. Otherwise, you get an error if v is not assigned prior to the his lambda definition.

I still donā€™t follow, sorry. The list is just an object passed in from outside the lambda as a function argument, no different to (or more ā€œexternalā€ than) the integer objects that would be passed in from outside the lambdas as function arguments in the two (non-anonymous) examples you gave. I could perhaps understand if you were concerned with mutating the list inside the lambda, or that you werenā€™t aware that lambdas could be written to accept multiple input parameters, but given your statements and examples, neither of these seems to be whatā€™s causing you the confusion here.

Can you define their lambda function without first defining (assigning) a list? In other words, can you delete the list v from the code and create the lambda function as they have defined it?

Yes, of course, same as with the parameters to any function. Arguments are only bound to the functionā€™s parameters when the function is called, not when it is defined, and the names inside and outside a function resides in separate scopesā€”thatā€™s the whole power of functions to begin with,

The user does so in their OP, and I do so here:

lambda v: {
    "open_time": float(v[0]),
    "open": float(v[1]),
    "high": float(v[2]),
    "low": float(v[3]),
    "close": float(v[4]),
}

This is perfectly valid code; the lambda function is defined without any need to ā€œpre-defineā€ a variable v, as indeed the parameter v inside the function is independent of any variable that might happen to be named v with the same name outside of it.

If I wanted to do something more useful, simply consider the minimally fixed version of the OPā€™s example:

def convert_lists_to_dicts(data):
    return list(
        map(
            lambda v: {
                "open_time": float(v[0]),
                "open": float(v[1]),
                "high": float(v[2]),
                "low": float(v[3]),
                "close": float(v[4]),
            },
            data,
        )
    )

Thereā€™s no v (or data) hardcoded here. map_data_to_dict could then be called with data at any later point like so:

convert_lists_to_dicts([(1, 2, 3, 4, 5), (6, 7, 8, 9, 10)])

Of course, as @jeff5 and I illustrate, this function could be written more concisely and elegantly a number of ways without needing a lambda, e.g.

FIELDS = ["open_time", "open", "high", "low", "close"]

def convert_lists_to_dicts(data):
    return [dict(zip(FIELDS, map(float, v))) for v in data]
2 Likes

Got it (talk about a eureka moment)! For some reason, since I only seen the lone v as a parameter and not a full fledged list, I was under the impression that you had to pre-define a list due to the individual indexes in the expression, which as I stated, were not part of the stated parameters in the function definition. This was the part that was throwing a wrench in between the neuronic gears.

Well, that definitely cleared things up.

Thank you a bunch.

Very much appreciated!

1 Like