-2

I would like to send two arguments within a function and receive two values as well

I want to modify this code so that I code be able to send two arguments and receive two as well

list_value = [ 1, 2,0,-1,-9,2,3,5,4,6,7,8,9,0,1,50]
hnd = map(lambda (valua): function_f(valua), list_value)

function_f is a function return one number either 1 or 0.

The above code can do the job when sending one argument but I want to send two instead of. the first argument of the required function is list_value and the second argument is a model "net model train it using caffe"

so I would like to write a function that can do the same job of the previous function but returning two arguments one is [0 or 1] and the other is a modified model which this function has modified.

S.AMEEN
  • 1,461
  • 4
  • 16
  • 23
  • 2
    Can you explain with a better example what you are trying to do here? – Anshul Goyal Jan 28 '16 at 15:01
  • 1
    your wording is weird but if you want to write a function that takes two inputs and returns two you can do `lambda a, b: (a+b, b-a)` you will need to return a tuple – user2255757 Jan 28 '16 at 15:03
  • 1
    you can't use such function with map – AlokThakur Jan 28 '16 at 15:04
  • 1
    @AlokThakur can he use `zip` to somehow arrange the list into pairs? – Shai Jan 28 '16 at 15:08
  • 1
    This gets much easier if you define the desired result *before* you start planning how to get there rather than the other way around. What do you want the end result to be? A list of `(0 or 1, current model state)` pairs? Or a list of "0 or 1", along with the final model state? Or something else? – molbdnilo Jan 28 '16 at 15:08
  • 3
    @Shai: Not needed with `map`; you can pass multiple iterables to `map`, and they will each be used as a source of positional arguments. So if you have: `map(lambda x, y: x + y, range(10), range(10, 20))` it will pass `0, 10`, then `1, 11`, etc. `zip` is only needed if the function in question requires the values to be tupled into one argument, rather than passed as two arguments. – ShadowRanger Jan 28 '16 at 15:11
  • 1
    @AlokThakur can you show us how? I am not very good at python `zip`ing... – Shai Jan 28 '16 at 15:11
  • 1
    You need to give an example of what you actually want here. Is it a single model object that is used with each input, modified, and reused for the next input? Or is there one model for each input? – ShadowRanger Jan 28 '16 at 15:13
  • 1
    @ShadowRanger so if I understand you correctly, you can `map( lambda(a,b): a+b, list_value[::2], list_value[1::2] )` to go over the list pair-by-pair? – Shai Jan 28 '16 at 15:13
  • 1
    @ShadowRanger this is not my question. I don't know what the OP wants. But I guess I could learn a bit of python along the way... Thank you for your help! – Shai Jan 28 '16 at 15:14
  • if its possible I want function can do like this list_value = [ 1, 2,0,-1,-9,2,3,5,4,6,7,8,9,0,1,50] hnd = map(lambda (valua): function_f(valua,model), list_value) where the model is caffe model – S.AMEEN Jan 28 '16 at 15:14
  • 2
    @Shai: Yup. Assuming `list_value` is of even length; if it's not, the (terrible) Py2 `map` will substitute `None` and run to the longest of the input iterables, Py3 `map` (and `itertools.imap` in Py2) will stop when the shortest iterable is exhausted. – ShadowRanger Jan 28 '16 at 15:15
  • 1
    @ShadowRanger Thanks! I am a little bit wiser now :) – Shai Jan 28 '16 at 15:19
  • 1
    @S.AMEEN and why is the code you propose not working? – Shai Jan 28 '16 at 15:21
  • @Shai I will try it again and many thanks for help – S.AMEEN Jan 28 '16 at 15:26

2 Answers2

6

Since you say you only want a single model, not a new model for each value, this is fairly simple. Change:

hnd = map(lambda (valua): function_f(valua), list_value)

to:

model = ... initialize a model that will be passed to every call ...
hnd = map(lambda valua: function_f(valua, model), list_value)

Just make sure function_f returns both the new value and model, e.g. if it previously did:

def function_f(val, model):
    ... calculate newval and make newmodel ...
    return newval

just change it to:

def function_f(val, model):
    ... calculate newval and make newmodel ...
    return newval, newmodel

Note: If need to use lambdas to use map, don't use map; it gains you nothing (a generator expression or list comprehension is going to run with the same speed or even faster in most cases where the mapping function isn't a CPython built-in). That said, in your particular case you don't need a lambda, for example, you can do:

from future_builtins import map  # Only on Py2; Py3 map is good

from itertools import repeat

model = ... initialize a model that will be passed to every call ...
hnd = map(function_f, list_value, repeat(model))

or just use a generator expression (unless the function is a Python built-in implemented in C, map basically never gains you performance; if you don't want to think about whether map is appropriate, always using list comprehensions/generator expresssions instead of map is a good idea):

# Change outside parens to brackets, [], for list comp
hnd = (function_f(x, model) for x in list_value)
ShadowRanger
  • 143,180
  • 12
  • 188
  • 271
3

By using zip, you can use map with such function. I am providing a sample code as you have asked to demonstrate

ls1 = [1,2,3,4,5]
ls2 = [1,2,3,4,5]
>>> def func(x,y):
    return x+1,y+1

>>> map(lambda (v1, v2): func(v1, v2), zip(ls1, ls2))
[(2, 2), (3, 3), (4, 4), (5, 5), (6, 6)]
AlokThakur
  • 3,599
  • 1
  • 19
  • 32
  • That would pass each `zip` output `tuple` as `v1`, and not provide a value for `v2`. You wouldn't get the output you provided, you'd get a `TypeError` for passing too few arguments to the `lambda`. [As I noted in the comments](https://stackoverflow.com/questions/35064747/send-two-argument-using-map-and-lambda-functions-and-return-two-values#comment57853226_35064747), you don't need/want to use `zip` when just pulling positional arguments from different iterables; `map` handles that already. To make it work with `zip`, you'd need to unpack those `tuple`s again, e.g. with `itertools.starmap`. – ShadowRanger Jan 28 '16 at 15:36
  • 1
    It's also silly to have a `lambda` when the function itself already takes the same args in the same order. `map(func, ls1, ls2)` would do this correctly, and much more succinctly. – ShadowRanger Jan 28 '16 at 15:37
  • @ShadowRanger, First of all It was just to demonstrate, It's not silly to have a lambda here,Because If you try to use map with same func directly, It throws error to me. map(func, zip(ls1, ls2)) (TypeError: func() takes exactly 2 arguments (1 given)) I hope you won't get this error. – AlokThakur Jan 28 '16 at 15:56
  • It would throw that error with or without the `lambda`; as I said, your code is wrong. Try actually running `map(lambda (v1, v2): func(v1, v2), zip(ls1, ls2))`, it breaks too, in the same way (I double checked, neither Py2 nor Py3 `map` has any special case that would support that line). That's why I said you don't want `zip`. – ShadowRanger Jan 28 '16 at 15:59
  • My code works with lambda and I am getting the result pasted above in answer – AlokThakur Jan 28 '16 at 16:01
  • Oh, whoops. I was running in on a different machine, and when retyping didn't include the parens around the args to the `lambda`; you were unpacking implicitly by including them (a normal `lambda` is defined without parens around the args, e.g. `lambda x, y:`). With the parens it works, you're just packing `tuple`s with `zip`, then unpacking immediately/implicitly in the `lambda`. You need the parens because of `zip`, but you missed that I'm not using `zip`: I suggested `map(func, ls1, ls2)`, no `zip` at all. Without the `zip`/`lambda`, it's faster, and no `TypeError`. – ShadowRanger Jan 28 '16 at 16:07
  • I hope you tried my code and verified your analysis, I have verified it on python 2.7 – AlokThakur Jan 28 '16 at 16:08
  • Neither of us were running the other's code. :-) You were adding `zip` to my code (which doesn't need it), I was subtracting parens from your code (which required them). Try actually running `map(func, ls1, ls2)` (no `zip`), you'll see that it works, and is a heck of a lot more concise (and faster). As a rule, if you need `lambda` to use `map`, then you're better off not using `map` (use a list comp or generator expr); `map` will be slower when you need a `lambda`. – ShadowRanger Jan 28 '16 at 16:10
  • Ok, @ShadowRanger I had the discussion on question, We agreed that it should be doable with zip and I was asked to provide a way to achieve with zip. I am ok in accepting that this is not best solution. – AlokThakur Jan 28 '16 at 16:12
  • I tried map(func, ls1, ls2) with my version of func, got Type error, Actually it is mentioned in question to use function which return two values. – AlokThakur Jan 28 '16 at 16:16
  • Okay, that's just confusing. `map(func, zip(ls1, ls2))` should get a `TypeError` because `zip` would be providing a single `tuple` arg instead of two args to `func`; with `map(func, ls1, ls2)`, it's passing two arguments, one from each input iterable, matching the args `func` expects. Retyping your code for `func`, I can only reproduce using `zip`. I cannot figure out how this is breaking for you; I assume an error on your part, but who knows? That said, the number of values returned from `func` is irrelevant; if `func` returns two-tuples, then `map` will produce an iterable of two-tuples. – ShadowRanger Jan 28 '16 at 16:32
  • ok, I think you are using python 3.x and I am using python 2.7 – AlokThakur Jan 28 '16 at 16:36
  • I actually tried in both, and tested with 2.7 (since your `map` returns `list`, that gave it away). It's not about 2.7 vs. 3.x; I can't reproduce your problem in 2.7. – ShadowRanger Jan 28 '16 at 16:59
  • @AlokThakur you should mention in the answer that it only works for Python2. Using parentheses to unpack the arguments in a lambda is not allowed in Python3. – Jakub Kukul May 18 '19 at 10:59