loops list slicing + elements allocation Python - python

I am pretty beginner in Python and trying to do the following:
main_list[80,80,30,30,30,30,20,10,5,4,3,2,1] #list of integers
- slicing the main_list in multiple lists for example list1,2,3,..,n with a sum of sub lists < 100
for i in range of n:
print(list(i))
list1[80,20], list2[80,10,5,4,1], list3[30,30,30], listn[30,3,2]
Thanks!

It's not really clear to me what you consider an acceptable output so I'm assuming that it's any list where its elements sum less than 100.
The solution I found is using recursion. For the list [a, b, c, d] we are going to check the condition for this sublists:
[a]
[a, b] (if the condition for [a] is met)
[a, b, c] (if the condition for [a, b] is met)
[a, b, c, d] (if the condition for [a, b, c] is met)
[a, c] (if the condition for [a] is met)
[a, c, d] (if the condition for [a, c] is met)
[a, d] (if the condition for [a] is met)
[b]
[b, c] (if the condition for [b] is met)
[b, c, d] (if the condition for [b, c] is met)
[b, d] (if the condition for [b] is met)
[c]
[c, d] (if the condition for [c] is met)
[d]
The concept is that for the "n" element in the list we are going to look for the sublists of size "n - 1" to 0 (so the element itself) that meet the requirements. The sublists are formed by the elements at the right of the studied element of each iteration, so for the first 30, the sublist to use would be [30, 30, 30, 20, 10, 5, 4, 3, 2, 1]
This process of finding the sublists for each element is the one that uses recursion. It calls itself for each element of the sublists checking if it meets the condition. For the example above, if the condition is met for [a, b] then it will also try for [a, b, c] and [a, b, d] (by calling itself with the sum of (a, b) and the sublist [c, d].
I've added a few prints so you can study how it works, but you should just use the results variable at the end of the script for getting your results.
main_list = [80,80,30,30,30,30,20,10,5,4,3,2,1]
def less_than_hundred(input) -> bool:
return input < 100
def sublists_meet_condition(condition, input):
"""
This function is used to call the sublists_for_element function with every element in the original list and its sublist:
- For the first element (80) it calls the second function with the sublist [80,30,30,30,30,20,10,5,4,3,2,1]
- For the fifth element (30) it calls the second function with the sublist [30,20,10,5,4,3,2,1]
Its purpose is to collect all the sublists that meet the requirements for each element
"""
results = []
for index, element in enumerate(input):
print('Iteration {} - Element {}'.format(index, element))
if condition(element):
results.append([element])
print('{} = {}'.format([element], element))
num_elements = len(input) - index
main_element = element
sublist = input[index+1:]
for result in sublists_for_element(condition, main_element, sublist):
new_result = [element] + result
sum_new_result = sum(new_result)
results.append(new_result)
print('{} = {}'.format([element] + result, sum_new_result))
return results
def sublists_for_element(condition, sum_main_elements, sublist):
"""
This function is used to check every sublist with the given condition.
The variable sum_main_elements allows the function to call itself and check if for a given list of numbers that meet the conditions [30, 30, 4] for example, any of the elements of the remaining sublists also meets the condition for example adding the number 3 still meets the condition.
Its purpose is to return all the sublists that meet the requirements for the given sum of main elements and remaining sublist
"""
num_elements = '{}{}'.format('0' if len(sublist) + 1 < 10 else '',len(sublist) + 1)
#print('Elements: {} | Main element: {} | Sublist: {}'.format(num_elements, sum_main_elements, sublist))
result = []
for index, element in enumerate(sublist):
if condition(sum_main_elements + element):
result.append([element])
sublist_results = sublists_for_element(condition, sum_main_elements + element, sublist[index+1:])
for sublist_result in sublist_results:
result.append([element] + sublist_result)
return result
results = sublists_meet_condition(less_than_hundred, main_list)

Related

Algorithm to determine which lists satisfy requirement

I got stuck coming up with an algorithm and I don't know what to do now.
I need to get from a to d but only by scrolling through these lists:
[e, d]
[a, b, c]
[d, a]
[a, b]
[a, e, b]
This is of course a simple example and the solution is:
[a → d] // 3rd line
[a → e → d] // 5th line + 1st line
[a → b → e → d] // 2nd + 5th + 1st line
But I have to solve it in Python.
I came up with two ways to solve this, the first was using for-loops, but the loops started repeating and got very time consuming, so I went with idea number 2.
I was thinking of creating a list of all possible variants that start with a and end with d. And then check if this is possible in our specified lists.
from itertools import permutations
lst = ['a', 'b', 'c', 'd', 'e']
x = 'a'
y = 'd'
for i in range(1, len(lst)):
perm = permutations(lst, i+1)
for j in list(perm):
if (j[0] == x) and (j[-1] == y):
print(j)
But then somehow I got stuck and I don't know what to do now. Could someone please give me a hint? Or am I going about this all wrong?
edit:
I'm trying to find all the paths and print them.
This is a graph problem where the lists are undirected edges between the nodes. For example:
[a, b, c]
means that there are undirected edges from a to b and c, from b to a and c, and from c to a and b. Of course, a -- b, also means b -- a. I have repeated the edges above only for clarity.
So, what you want to do is to create an adjacency list that represents all of these edges and apply backtracking since you want all the possible paths from source to target.
Here is some code that shows you the idea:
adj_list = collections.defaultdict(set)
for row in rows:
for i, el in enumerate(row):
for j in range(i+1, len(row):
adj_list[el].add(row[j])
adj_list[row[j]].add(el)
def backtrack(node, adj_list, seen, partial_res, res):
if node == target:
res.append(partial_res[:])
for neighbor in adj_list[node]:
if neighbor in seen: continue
seen.add(neighbor)
partial_res.append(neighbor)
backtrack(neighbor, adj_list, seen, partial_res, res)
partial_res.pop()
seen.remove(neighbor)
res = []
backtrack(start, adj_list, set(), [], res)
print(res)
I haven't run this. But the code should give an idea of how backtracking works. It's a dfs where you check each possible path and keep track of the edges that you traveled. If it leads to destination, you save a copy of it in your final results.
Please note that this algorithm only visit each node once in each path.

next item of list inside dataframe

I have a dataframe that has a column where each row has a list.
I want to get the next element after the value I am looking for (in another column).
For example:
Let's say I am looking for 'b':
|lists |next_element|
|---------|------------|
|[a,b,c,d]| c | #(c is the next value after b)
|[c,b,a,e]| a | #(a is the next value after b)
|[a,e,f,b]| [] | #(empty, because there is no next value after b)
*All lists have the element. There are no lists without the value I am looking for
Thank you
Try writing a function and use apply.
value = 'b'
def get_next(x):
get_len = len(x)-1
for i in x:
if value.lower() == i.lower():
curr_idx = x.index(i)
if curr_idx == get_len:
return []
else:
return x[curr_idx+1]
df["next_element"] = df["lists"].apply(get_next)
df
Out[649]:
lists next_element
0 [a, b, c, d] c
1 [c, b, a, e] a
2 [a, e, f, b] []
First observation, since you want the next element of a list of string elements, the expected data type should be a string for that column, and not a list.
So, instead of the next_element columns as [c, a, []] its better to use [c, a, None]
Secondly, you should try avoiding apply methods directly over series and instead utilize the str methods that pandas provides for series which is a vectorized way of solving such problems super fast.
With the above in mind, let's try this completely vectorized one-liner -
element = 'b'
df['next_element'] = df.lists.str.join('').str.split(element).str[-1].str[0]
lists next_element
0 [a, b, c, d] c
1 [c, b, a, e] a
2 [a, e, f, b] NaN
First I combine each row as a single string [a,b,c,d]->'abcd`
Next I split this by 'b' to get substrings
I pick the last element from this list and finally the first element from that, for each row, using str functions which are vectorized over each row.
Read more about pandas.Series.str methods on official documentation/tutorial here
df = df.assign(next_element = "")
print(df)
for ind in df.index:
c= df["Lists"][ind]
for i,v in enumerate(c):
if v == "b":
df["next_element"][ind] = c[i+1]
print(df)
Try with this one you will get the exact output what you expected.

Simultaneously iterate over multiple list and capture difference in values

Consider API returning four lists as output. Let's consider output as
a = [1,2,3,4]
b = [1,2,3,4]
c = [1,2,4,3]
d = [1,2,3,5]
Now, first we want to compare these lists are equal or not.
Lists are equal only if elements and there indexes matches.
For example, from above lists, a and b are equal. But a and c are not equal.
If the lists are not equal, then output is expected as: this element at this index in this list is not same as other.
For comparing and getting differences of two lists, I have written below code.
for i in range(len(a)):
if a[i] != c[i]:
print "Expected value at ",i," is ",a[i]
print "But got value ",c[i],"in second list"
Now question is how to achieve this for all four above lists?
You may use zip to iterate over each list simultaneously and compare the value at each index. In the below example, I am comparing the value of list a with remaining lists.
a = [1,2,3,4]
b = [1,2,3,4]
c = [1,2,4,3]
d = [1,2,3,5]
for i, x in enumerate(zip(a, b, c, d)):
print('--------- Index: {}'.format(i))
base = x[0]
for j, y in enumerate(x[1:], 2):
if base!=y:
print('{} not equal to {} : --> List {}'.format(base, y, j))
which prints:
--------- Index: 0
--------- Index: 1
--------- Index: 2
3 not equal to 4 : --> List 3
--------- Index: 3
4 not equal to 3 : --> List 3
4 not equal to 5 : --> List 4
From the comment:
How to find in which list we have different value?
import collections as ct
counter = ct.Counter(map(tuple, [a,b,c,d])) # make hashable keys w/tuples
base = counter.most_common(1)[0][0] # find most frequent sequence
[list(seq) for seq in counter if seq != base] # filter uncommon sequences
Output (the non-matching lists):
[[1, 2, 4, 3], [1, 2, 3, 5]]
We collect all similar sequences as keys in a collections.Counter. If all sequences match, there should only be one entry in the Counter dictionary. Otherwise, filter the remaining sequences.
Set up a list mylist = [a, b, c,d] Then loop through checking which ones are equal and which ones are not equal.
for i in range(len(mylist)-1)
for j in range(i+1, len(mylist))
# Check mylist[i] agaist mylist[j] and report results
For example, this will test a against b, c, and d
b against c and d
c against d

Using itertools.permutation where r > n

I am trying to generate all permuations of a set of items and the my R needs to be larger than the size of the set of items
Here is an example :
itertools.permutations ("ABC", 4)
this always returns 0 items as R > N.
I want this
[A, A, A, A]
[A, A, A, B]
[A, A, B, A]
[A, B, A, A]
...
How can I achieve this?
You don't seem to want the permutation, but the Cartesian product:
itertools.product("ABC", repeat=4)
https://docs.python.org/3/library/itertools.html#itertools.product

Python list check if 2 largest values are the same

In python, is it possible to check if the 2 largest values in a list are the same?
This is my code:
list=[[A, teamAScore], [B, teamBScore], [C, teamCScore], [D, teamDScore]]
list.sort()
print(max(list))
If the largest 2 values are the same, the max function will only return one of them. Is there a way to check if the two last values in the list are the same, so I can compare them in a different way? (Separate function etc etc)
A, B, C and D are Strings. teamAScore etc. are integers
I presume you want the max based on the score i.e the second element so first get the max based on the second element of each sublists scores then keep all sublists that have a score equal to the max:
from operator import itemgetter
lst = [[A, teamAScore], [B, teamBScore], [C, teamCScore], [D, teamDScore]]
# get max of list based on second element of each sublist i.e teamxScore
mx = max(lst,key=litemgetter(1)))
# use a list comp to find all sublists where teamxScore is equal to the max
maxes = [ele for ele in lst if ele[1] == mx[1]]
Demo:
l = [["foo", 2], ["bar", 1], ["foobar", 2]]
mx = max(l, key=itemgetter(1))
maxes = [ele for ele in l if ele[1] == mx[1]]
Output:
[['foo', 2], ['foobar', 2]]
Both foo and foobar had a score equal to the max so we get both sublists returned.

Categories