I'm trying to write a code that uses only lambdas, filter, map and reduce (its a riddle) that accepts a tuple of integers and a tuple of functions, and returns a new tuple of integers who only return one true from the list of functions:
As an example, if the tuple is (1, 2, 3, 4, 5, 6, 7, 8, 9, 10) and the tuple of functions is (lambda x: x > 3, lambda x: x % 2 == 0) I should get a new tuple that looks like [2, 5, 7, 9] because they make only one of the two rules to return True. this is my code so far and I have no idea how to do that...
func = (lambda x: x > 3, lambda x: x % 2 == 0)
data = (1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
a = lambda func, data: tuple(filter(lambda x: tuple(filter(None, map(lambda f: f(x), func))), data))
print(a(func, data))
This code returns only the integers that apply to both of the terms, but I need to make it to just one.
Here it is:
a = lambda func, data: tuple(filter(lambda d: (sum(map(lambda f: f(d), func)) == 1), data))
Since this really is just a contrived exercise for the sake of it I won't endeavor explaining this horrible expression. But the way to get to it is to first write the code in a clear way with for loops, if blocks etc..., and then one step at a time replace each component with the appropriate map, filter etc...
The one trick I use here is automatic boolean conversion to int: sum(sequence_of_bool) == 1 means exactly one bool is True.
My full test code:
func = (lambda x: x > 3, lambda x: x % 2 == 0)
data = (1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
a = lambda func, data: tuple(filter(lambda d: (sum(map(lambda f: f(d), func)) == 1), data))
print(a(func, data))
(2, 5, 7, 9)
You can use bool.__xor__ to ensure that only one of the two functions in the func tuple is satisfied:
from functools import reduce
tuple(filter(lambda x: reduce(bool.__xor__, map(lambda f: f(x), func)), data))
This returns:
(2, 5, 7, 9)
Related
Why does this code print 2?
I'm having a hard time wrapping my head around the order of the calls and what happens when the code runs. I'd like to know what's going on here, thanks!
The code:
mia = lambda dan: lambda john: list(john)[dan]
john = lambda mia: lambda dan: filter(dan, map(lambda x: x % 2 + 1, mia))
ta = mia(-1)(john([3, 6, 9, 12, 15])(lambda f: f % 3))
print(ta)
This is some kind of obfuscated way to perform a simple task:
check if numbers in a list are odd or even and map 1, 2 accordingly
filter the previous output if this is not a multiple of 3 (which is always True)
take the last item of the previous output
In summary, this output 2 if the last number of the input is odd and 1 otherwise.
This could be simplified to:
list(map(lambda x: x % 2 + 1, [3, 6, 9, 12, 15]))[-1]
or, keeping the useless filter:
list(filter(lambda f: f % 3, map(lambda x: x % 2 + 1, [3, 6, 9, 12, 15])))[-1]
This is using a functional approach in which the functions return functions instead of values. In addition the local variables have names designed to be confusing (mia in john has nothing to do with the mia function)
Interestingly, mia is equivalent to operator.itemgetter
It does a lot less than it looks like.
To simplify, turn the lambda expressions into def statements.
def mia(dan):
def inner(john):
lst = list(john)
return lst[dan]
return inner
def john(mia):
def inner(dan):
mp = map(lambda x: x % 2 + 1, mia)
return filter(dan, mp)
return inner
To simplify further, separate your function calls.
# just return the inner function
john_inner_func = john([3, 6, 9, 12, 15])
# first map element % 2 + 1 to each element of the given array
# this results in [2, 1, 2, 1, 2]
# next it filters all truthy (non-zero) values of the result of element % 3.
# Since all are positive and less than 3 the result is the same
# [2, 1, 2, 1, 2]
john_filter_result = john_inner_func(lambda f: f % 3)
# just return the inner function
mia_inner_func = mia(-1)
# return the -1 index of the filter result as a list
# this gives the last element, or 2
ta = mia_inner_func(john_filter_result)
print(ta)
I have a huge dataset with about 20 columns.
I'm working with rdds in pyspark and need to do something like
rdd.map(lambda x: (x[9], x[:] - x[9]))
basically. create a ley value pair such that one of the columns is the key and rest of them are values. I'm unable to slice it in a way that makes sense.
i've tried
rdd.map(lambda x: (x[9], x[:] - x[9]))
rdd.map(lambda x: (x[9], x[:8] + x[10:]))
rdd.map(lambda x: (x[9], list(x[:8].append(x[10:]))))
none of it seems to be working. I'm not sure what the right way to do it would be
I would break the problem into steps.
# First we set it up
data = [(1,2,3,4,5,6,7,8,9,10)] # one row
rdd = spark.sparkContext.parallelize(data)
rdd.collect()
#[(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)]
Next we need a function that pops a value from a tuple and makes it a key.
def key_elem_to_rest(key_index, tup):
l = list(tup)
key = l.pop(key_index)
return {key: tuple(l)}
Next up we use it in the map
rdd.map(lambda x: key_elem_to_rest(0, x)).collect() # index = 0
#[{1: (2, 3, 4, 5, 6, 7, 8, 9, 10)}]
rdd.map(lambda x: key_elem_to_rest(5, x)).collect() # index = 5
#[{6: (1, 2, 3, 4, 5, 7, 8, 9, 10)}]
You can try using this:
rdd.filter(lambda x: x[0] != x[9]).map(lambda x: (x[9], [x[:-1]]))
This is checking if the x[9] is not a key and it is making it as a key and rest as value.
I finally figured it out myself.
units_rdd1 = units_rdd.map(lambda x: (x[9], list(x[0:9]+x[10:])))
This is my list: a = [1, 3, 4, 7, 8, 9, 12, 13, 14].
I want to get the number that is closest to 5, this is the solution:
b = min(a, key = lambda x: abs(x-5))
Please explain what is happening in the above line.
The code is using the min builtin function, but with a key parameter. Thus, it does not return the actual minimum element of the list, but the element for which that key function is minimal, i.e. it behaves more like "arg-min" than actually "min".
In the key function (defined as a lambda expression), abs is just the absolute difference, in this case between the parameter x (a number from the list) and 5.
That line is somewhat equivalent to, but much shorter and more readable than, this loop:
a = [1,3,4,7,8,9,12,13,14]
b = min_k = None
for x in a:
k = abs(x-5)
if min_k is None or k < min_k:
b, min_k = x, k
Explanation
min(iterable, key) returns the smallest item in the iterable with respect to the key. So it iterates over the iterable, each time evaluates the key(x) for an element x, and then returns the element for which key(x) was the smallest.
Since key=lambda x=abs(x-5), we thus evaluate the absolute difference between 5, so if x=3, then abs(x-5) is 2, etc. So this will result in the number that is the closest to 5.
Making this an O(log n) algorithm
Given the list is ordered, you can find this in logarithmic time with:
from bisect import bisect_left
def closest(ordered_list, x):
idx = bisect_left(ordered_list, x)
return min(ordered_list[max(idx-1,0):idx+1], key=lambda y: abs(y-x))
For example:
>>> closest(a, -1)
1
>>> closest(a, 0)
1
>>> closest(a, 1)
1
>>> closest(a, 2)
1
>>> closest(a, 3)
3
>>> closest(a, 4)
4
>>> closest(a, 5)
4
>>> closest(a, 6)
7
>>> closest(a, 11)
12
>>> closest(a, 15)
14
abs(x-5)
abs is absolute mathematics function which is equivalent to |x-5|.
example : abs(x-5) when x=6 is 1, and when x=4 is also 1.
lambda x: abs(x-5)
It can be written as
def func(x):
return abs(x-5)
which means for a = [1,3,4,7,8,9,12,13,14]
lambda x: abs(x-5)
will give
[4, 2, 1, 2, 3, 4, 7, 8, 9]
key = lambda x: abs(x-5)
Here the value returned by this lambda function is stored in key variable.
Thus
key = [4, 2, 1, 2, 3, 4, 7, 8, 9]
Lastly min(a, key)
The min function uses key as an iterable to calculate minimum value.
Using the position of minimum value obtained from key it displays the value from iterable a.
Thus for
key = [4(0), 2(1), 1(2), 2(3), 3(4), 4(5), 7(6), 8(7), 9(8)]
minimum value is 1 at position 2 and it displays value at 2 position from iterable a
[1(0), 3(1), 4(2), 7(3), 8(4), 9(5), 12(6), 13(7), 14(8)]
which is 4.
try this
import numpy as np
def return_closest(a, num):
m1 = a[np.searchsorted(a, num)]
m2 = a[np.searchsorted(a, num)-1]
return m2 if abs(num-m1)>abs(num-m2) else m1
a = [1, 3, 4, 7, 8, 9, 12, 13, 14]
return_closest(a, 5)
gives 4
the function np.searchsorted will give you index of the upper limit (7)
Suppose a generator yields the below tuples one by one (from left to right)
(1, 2, 3), (2, 5, 6), (3, 7, 10), (4, 5, 11), (3, 5, 15), (4, 5, 9), (4, 6, 12)
...
and suppose I'd like to iterate as long as the predicate is true. Let that predicate be sum(yielded_value) < 20. Then the iterator will stop by (3, 5, 15). I can do it with, say:
list(itertools.takewhile(lambda x: sum(x) < 20, some_generator()))
Question, how do I write a similar expression with two predicates? Suppose I want:
list(itertools.takewhile(lambda x: sum(x) < 20 and first_value_of_tuple > 3, some_generator()))
(which, in this case, stop by (4, 6, 12).)
You can access to elements of each tuple with index.
list(itertools.takewhile(lambda x: sum(x) < 20 and x[0] > 3, some_generator()))
Since everything in itertools is lazily iterated, and you are using and for two predicates, you can simply use two takewhile iterators. Sometimes I find this more readable than putting both predicates in a single predicate function or lambda:
lessthan20 = itertools.takewhile(lambda x: sum(x) < 20, some_generator())
greaterthan3 = itertools.takewhile(lambda x: x[0] > 3, lessthan20)
list(greaterthan3)
It also makes it so that you don't have a single huge one liner if you need to add even more predicates in the future.
If you have additional predicates and need to access all the elements of your tuples you can also unpack them in your lambda function:
list(itertools.takewhile(lambda (x, y, z): x+y+z < 20 and x > 3 and y < 7 and z > 1, some_generator()))
This also asserts that all your tuples have length 3. If you get a tuple with 4 values, it fails hard, as opposed to continuing silently. Obviously only useful in some contexts.
Im trying to write a function that creates set of dynamic sublists each containing 5 elements from a list passed to it.Here's my attempt at the code
def sublists(seq):
i=0
x=[]
while i<len(seq)-1:
j=0
while j<5:
X.append(seq[i]) # How do I change X after it reaches size 5?
#return set of sublists
EDIT:
Sample input: [1,2,3,4,5,6,7,8,9,10]
Expected output: [[1,2,3,4,5],[6,7,8,9,10]]
Well, for starters, you'll need to (or at least should) have two lists, a temporary one and a permanent one that you return (Also you will need to increase j and i or, more practically, use a for loop, but I assume you just forgot to post that).
EDIT removed first code as the style given doesn't match easily with the expected results, see other two possibilities.
Or, more sensibly:
def sublists(seq):
x=[]
for i in range(0,len(seq),5):
x.append(seq[i:i+5])
return x
Or, more sensibly again, a simple list comprehension:
def sublists(seq):
return [seq[i:i+5] for i in range(0,len(seq),5)]
When given the list:
l = [1,2,3,4,5,6,7,8,9,10]
They will return
[[1, 2, 3, 4, 5], [6, 7, 8, 9, 10]]
Have you considered using itertools.combinations(...)?
For example:
>>> from itertools import combinations
>>> l = [1,2,3,4,5,6]
>>> list(combinations(l, 5))
[(1, 2, 3, 4, 5), (1, 2, 3, 4, 6), (1, 2, 3, 5, 6), (1, 2, 4, 5, 6), (1, 3, 4, 5, 6), (2, 3, 4, 5, 6)]
By "dynamic sublists", do you mean break up the list into groups of five elements? This is similar to your approach:
def sublists(lst, n):
ret = []
i = 0
while i < len(lst):
ret.append(seq[i:i+n])
i += n
return ret
Or, using iterators:
def sublists(seq, n):
it = iter(seq)
while True:
r = list(itertools.islice(it, 5))
if not r:
break
yield r
which will return an iterator of lists over list of length up to five. (If you took out the list call, weird things would happen if you didn't access the iterators in the same order.)