Looping a list of lists, while accessing each elements easily - python-3.x

I apologise in advance if this has been answered before, I didn't know what to search for.
Say, I want to iterate through a list of lists that looks like this:
x = [[a, b, c], [a, b, c], ...]
I figured out I can do this to easily access the lists inside that structure:
for [a, b, c] in x:
doSomethingToElements(a,b,c)
What I want to do is:
for [a, b, c] as wholeList in x:
doSomethingToElements(a,b,c)
doSomethingToWholeLists(wholeList)
However, that syntax is invalid, is there any equivalent way to do it, which is correct and valid?
Or should I do it with enumerate() as stated here?
EDIT: Working through to make enumerate() work, I realise I can do this:
for idx, [a, b, c] in enumerate(x):
doSomethingToElements(a,b,c)
doSomethingToWholeLists(x[idx])
But feel free to post more elegant solutions, or is it elegant enough that it doesn't matter?

There are two options.
The first one is iterate element and list together using zip, and the second one is iterate the list and assign each value.
x = [[1, 2, 3], [4, 5, 6]]
for (a, b, c), z in zip(x, x):
print(a, b, c, z)
for z in x:
a, b, c = z
print(a, b, c, z)

There is not really any syntax similar to that suggestion. Your best bet would be splat-unpacking:
for wholeList in x:
doSomethingToElements(*wholeList)
doSomethingToWholeLists(wholeList)

Related

Dynamic Python function parameter rerouting

I have a python function
func(a, b, c, d, e).
I want to pass this function to another function that evaluates it. The catch is that this other function only varies an arbitrary subset of the parameters (a, b, c, d, e), and the other parameters shall be preloaded with a constant. The parameter order may also change.
For example: I would like func_2 to vary a, c, and d, while b=3 and e=4. So I need a routine
def convert(func, variables=[3, 0, 2], constants=[1, 4], vals=[3, 4]):
...
python magic
...
return func_2
that converts:
func(a, b, c, d, e) -> func_2(d, a, c, b=3, e=4),
so that when I call func_2(1, 2, 3), what is actually called behind the scenes is func(2, 3, 3, 1, 4).
(This is for an optimization algorithm that operates on subspaces of a parameter space, and these subspaces can change from cycle to cycle. func is a cost function.)
How do I code convert in Python 3?
This works:
def convert(func, vars, fixed):
# vars: list of indices
# fixed: dictionary mapping indices to constants
n = len(vars) + len(fixed)
def func_2(*args):
newargs = [None] * n
for i, j in enumerate(vars):
newargs[j] = args[i]
for k in fixed:
newargs[k] = fixed[k]
return func(*newargs)
return func_2
Here you have a possible solution:
def convert(func, var, const, vals):
def func2(*args):
params = [args[var.index(i)] if i in var
else vals[const.index(i)]
for i in range(len(var)+len(const))]
return func(*params)
return func2
It works with any number of parameters

Combining 2 lists with streams in Groovy

Say I have two lists of equal size [1, 2, 3, 4, ...] and [a, b, c, d, ...]. Is there a way I make a map with streams that maps 1 to a, 2 to b, 3 to c, and so on without using lambda functions or nested functions?
I would use map and pass in a function, but this passed-in function can only take 1 argument and I need both pieces of information to map the elements to each other.
IntStream(1, list1.size()).stream().map(this.&combineListsFunction).collect...
combineListsFunction can only use the information from the stream, but I need both lists for the function to work.
You can transpose both lists (which will give you a list of tuples and then create the map from it with collectEntries() (which takes exactly this). E.g.:
def l1 = [1,2,3]
def l2 = ["a","b","c"]
assert [(1): "a", (2): "b", (3): "c"] == [l1,l2].transpose().collectEntries()

Python reduce & Lambda with multiple params

Is There any way by which I could use 3 variables in reduce(lambda f) combination like
reduce(lambda a, b, c : a*b+c, <list_for_a&b>, <range_for_c>)
I can use map() function. But thought of knowing a new possibility, if any.
You can zip the two sequences and them work on the result.
values_for_a_and_b = ... # I assume this is a list of tuples
values_for_c = ... #
product = zip(values_for_a_and_b, values_for_c) # This gives a list like [((a, b), c)]
Now it looks like you're trying to do a map, rather than a reduce.
You can use the product as follows:
map(lambda x: x[0][0] * x[0][1] + x[1], product)
But since Python doesn't have pattern matching, it's not really elegant.

Search for sequence of items in a list

Is there an easy way to search for a sequence of strings in a list? For example:
testlist = [a,b,c,d,e,f,g,a,b,c,d,j,k,j]
and I want to search for the sequence abc and getting the index returned. So to clarify if the string I want to search consists of more than one element of the list. For some context: I have a list with datablocks and I want to find out how big each datablock is therefore searching for a reoccuring string in the list.
There are many good string search algorithms: KMP, Boyer-Moore, Rabin-Karp. You can use the builtin str.index function on ''.join(L) if you are dealing with characters (str.index implements Boyer-Moore algorithm in CPython: https://github.com/python/cpython/blob/3.7/Objects/stringlib/fastsearch.h).
But in most cases, the naive algorithm is good enough. Check every index of the haystack to find the needle:
>>> a, b, c, d, e, f, g, j, k = [object() for _ in range(9)]
>>> haystack = [a, b, c, d, e, f, g, a, b, c, d, j, k, j]
>>> needle = [a, b, c]
>>> for i in range(len(haystack)-len(needle)+1):
... if haystack[i:i+len(needle)] == needle:
... print(i)
...
0
7
The complexity is O(|haystack|*|needle|).

Merge items from separate lists into nested lists

Hello I am trying to merge two lists sequentially into sub lists. I wonder if this is possible without list comprehensions or a lambda operation as I'm still learning how to work with those approaches. Thank you
a = [0,1,2,3]
b = [4,5,6,7]
#desired output
c = [0,4],[1,5],[2,6],[3,7]
An approach that doesn't involve lambdas or list comprehensions (not sure what the issue is with list-comps) would be with map:
c = list(map(list, zip(a, b)))
This first zips the lists together, then creates a list instance for every tuple generated from zip with map and wraps it all up in list in order for map to yield all it's contents:
print(c)
[[0, 4], [1, 5], [2, 6], [3, 7]]
This, at least in my view, is less understandable than the equivalent comprehension John supplied in a comment.
Here’s a solution suitable for beginners!
c = []
a = [0,1,2,3]
b = [4,5,6,7]
for i in range(min(len(a), len(b))):
c.append([a[i], b[i]]) # writing [a[i], b[i]] creates a new list
print(c)

Resources