Unwrapping a list from the inside - python

I am updating a legacy Python script, and was wondering if it is possible to unwrap a list from inside another list, or more generally to unwrap a list into just its elements.
My specific problem is that I have a large list, and now am being passed another list to place in the middle of this list, instead of a single element, i.e. I have a list of the form [1,2,3,'passed parameter',4,5], and I am now being passed a list of the form ['list','of','parameters'], with the goal of generating the list [1,2,3,'list','of','parameters',4,5].
The obvious solution to this is to write [1,2,3] + ['list','of','parameters'] + [4,5] but I am worried that this will iterate over ['list','of','parameters'] and [4,5], instead of just the ['list','of','parameters']. (This matters because apart from being in a performance critical part of the program, the elements of the list are expensive to evaluate.)

It's not entirely clear what you mean - how are you determining where to place the list? - but you can use slicing to do this.
original_list = [1, 2, 3, 4, 5]
new_list = [2, 3, 4]
original_list[3:3] = new_list

Related

What is wrong with my function to get all subsets of a list?

def getAllSubsets(lst):
"""
lst: A list
Returns the powerset of lst, i.e. a list of all the possible subsets of lst
"""
if not lst:
return []
withFirst = [[lst[0]] + rest for rest in getAllSubsets(lst[1:])]
withoutFirst = getAllSubsets(lst[1:])
return withFirst + withoutFirst
I don't fully understand how it is managing to getAllSubsets of given list. This function was provided to me, not written by me. An explanation of how it works would be appreciated.
Karl has already pointed out the error in the original code, and I think explanations have been offered for how the recursion works, but we can also make the code shorter in the following way:
def powersetlist(s):
r = [[]]
for e in s:
r+=[x+[e] for x in r]
return r
Here, we update what is in r at every element e in our list s, and then add the new subsets with e to our existing r. I think we avoid recursion in this case.
Output for [1,2,3,4]:
[[], [1], [2], [1, 2], [3], [1, 3], [2, 3],
[1, 2, 3], [4], [1, 4], [2, 4], [1, 2, 4],
[3, 4], [1, 3, 4], [2, 3, 4], [1, 2, 3, 4]]
Your question title and question body are contradictory, as the former makes it sound like there's a problem with the program and you're trying to figure out what it is. The problem with the program is that the line return [] is returning an empty list, when instead it should be returning a list containing an empty list. As for the body of the question, that is asking for an explanation for how the program is supposed to work:
The basic idea of the program that given an original set A and subset B, it is the case that for every element of A, it either is or isn't in B. That is, B can be constructed by going through each element of A, and for that element, making a decision as to whether to include it or not. This then suggests a recursive algorithm for creating subsets: given a set A, consider the "tail" of A. By that I mean, all the elements of A other than the "first" one (sets don't really have a first element, but the input to this function is actually a list, rather than a set, so there is a first element). Find all the subsets for the tail of A, then, for each subset that you find that way, create two subsets: one that includes the first element of A, and another that doesn't.
So how the algorithm works is that it sets the first element of the input aside, then calls the function on the remaining elements, get all the resulting subsets, and for each of them creates two subsets, one with and one without the element that was set aside. Of course, if you keep removing the first element, you'll eventually get an empty list. So the algorithm first checks whether the list is empty, and if so, returns that the only subset is the null set.
There are some ways the function can be improved. The biggest thing is that it calls getAllSubsets(lst[1:] twice. Unless you have a really smart compiler/interpreter that can recognize that and only actually run it once, you're doing much more work than you need to. I think it's even more than twice as much work, because you're doubling the amount of work at each level of recursion. So if there are five levels of recursion, you'll be running the lowest level 32 times as much. You could also hardcode the first level of recursion by just taking the null set and the element, although that's somewhat abandoning the simplicity of a pure recursion algoritm.
def getAllSubsets(lst):
"""
lst: A list
Returns the powerset of lst, i.e. a list of all the possible subsets of lst
"""
if not lst:
return [[]]
# you can remove the above two lines if you're sure
# that the original call isn't on an empty list
tail = lst[1:]
if not tail:
return [[],[lst[0]]
tail_subsets = getAllSubsets(tail)
withFirst = [[lst[0]] + rest for rest in tail_subsets]
return tail_subsets + withFirst

how do I append a list with two variables to another list that already has that list in it but with different values? python

I'm doing my programming coursework, and I've come across an issue
gamecentre1 = [winnerscore, winner]
organise = []
organise.extend([gamecentre1])
from operator import attrgetter, itemgetter
sorted(organise, key= itemgetter(0))
print(organise)
f = open("gameresults.txt","w")
f.write("Here are the winners of the games: \n")
f.write(str(organise))
f.write("\n")
f.close()
I'm trying to add two variables to a list, and add that list to another list. Then, I want to organise that larger list based off of the integer variable of the sublist (the integer is the winnerscore). But, the problem is that I haven't been able to organise them properly, and I worry that since I have to append the same list with the same variables to the larger list without overwriting the existing list in it, the larger list will just have the same values over and over again.
This is because I want to store the variables every time the program runs, without getting rid of the values of the variable from the previous game.
How do I do this?
I'm trying to add two variables to a list, and add that list to another list. Then, I want to organise that larger list based off of the integer variable of the sublist
It sounds like what you want is a nested list - a big list of small lists, such that each small list is independent of the others. The key problem in your code right now that's blocking you from accomplishing this is extend() - this is essentially list concatenation, which isn't what you want. For example,
x = [1, 2]
x.extend([3, 4]) # x == [1, 2, 3, 4]
Instead, try using append(), which adds its argument as the next value in the list. For example:
x = []
x.append([3, 4]) # [[3, 4]]
x.append([1, 2]) # [[3, 4], [1, 2]]
Now in the above example, we have a list x that's two elements long, and each of those elements is itself a list of two elements. Now we can plug that into sort:
y = sorted(x, key=lambda i: i[0])
print(y)
# [[1, 2], [3, 4]]
(the lambda i: i[0] is really just a more elegant way of what you're doing with itemgettr(0) - it's a lambda, a small inline function, that takes one argument i and returns the 0th element of i. In this case, the i that gets passed in is one of the smaller lists).
Now you have a sorted list of smaller lists, and you can do whatever you need with them.

Rearrange list in-place by modifying the original list, put even-index values at front

I am relatively new to python and I am still trying to learn the basics of the language. I stumbled upon a question which asks you to rearrange the list by modifying the original. What you are supposed to do is move all the even index values to the front (in reverse order) followed by the odd index values.
Example:
l = [0, 1, 2, 3, 4, 5, 6]
l = [6, 4, 2, 0, 1, 3, 5]
My initial approach was to just use the following:
l = l[::-2] + l[1::2]
However, apparently this is considered 'creating a new list' rather than looping through the original list to modify it.
As such, I was hoping to get some ideas or hints as to how I should approach this particular question. I know that I can use a for loop or a while loop to cycle through the elements / index, but I don't know how to do a swap or anything else for that matter.
You can do it by assigning to a list slice instead of a variable:
l[:] = l[::2][::-1] + l[1::2]
Your expression for the reversed even elements was also wrong. Use l[::2] to get all the even numbers, then reverse that with [::-1].
This is effectively equivalent to:
templ = l[::2][::-1] + l[1::2]
for i in range(len(l)):
l[i] = templ[i]
The for loop modifies the original list in place.

How to get the second half of a list of lists as a list of lists?

So I know that to get a single column, I'd have to write
a = list(zip(*f)[0])
and the resulting a will be a list containing the first element in the lists in f.
How do I do this to get more than one element per list? I tried
a = list(zip(*f)[1:19])
But it just returned a list of lists where the inner list is the composed of the ith element in every list.
The easy way is not to use zip(). Instead, use a list comprehension:
a = [sub[1:19] for sub in f]
If it is actually the second half that you are looking for:
a = [sub[len(sub) // 2:] for sub in f]
That will include the 3 in [1, 2, 3, 4, 5]. If you don't want to include it:
a = [sub[(len(sub) + 1) // 2:] for sub in f]
You should definitely prefer #zondo's solution for both performance and readability. However, a zip based solution is possible and would look as follows (in Python 2):
zip(*zip(*f)[1:19])
You should not consider this cycle of unpacking, zipping, slicing, unpacking and re-zipping in any serious code though ;)
In Python 3, you would have to cast both zip results to list, making this even less sexy.

Removing duplicates and preserving order when elements inside the list is list itself

I have a following problem while trying to do some nodal analysis:
For example:
my_list=[[1,2,3,1],[2,3,1,2],[3,2,1,3]]
I want to write a function that treats the element_list inside my_list in a following way:
-The number of occurrence of certain element inside the list of my_list is not important and, as long as the unique elements inside the list are same, they are identical.
Find the identical loop based on the above premises and only keep the
first one and ignore other identical lists of my_list while preserving
the order.
Thus, in above example the function should return just the first list which is [1,2,3,1] because all the lists inside my_list are equal based on above premises.
I wrote a function in python to do this but I think it can be shortened and I am not sure if this is an efficient way to do it. Here is my code:
def _remove_duplicate_loops(duplicate_loop):
loops=[]
for i in range(len(duplicate_loop)):
unique_el_list=[]
for j in range(len(duplicate_loop[i])):
if (duplicate_loop[i][j] not in unique_el_list):
unique_el_list.append(duplicate_loop[i][j])
loops.append(unique_el_list[:])
loops_set=[set(x) for x in loops]
unique_loop_dict={}
for k in range(len(loops_set)):
if (loops_set[k] not in list(unique_loop_dict.values())):
unique_loop_dict[k]=loops_set[k]
unique_loop_pos=list(unique_loop_dict.keys())
unique_loops=[]
for l in range(len(unique_loop_pos)):
unique_loops.append(duplicate_loop[l])
return unique_loops
from collections import OrderedDict
my_list = [[1, 2, 3, 1], [2, 3, 1, 2], [3, 2, 1, 3]]
seen_combos = OrderedDict()
for sublist in my_list:
unique_elements = frozenset(sublist)
if unique_elements not in seen_combos:
seen_combos[unique_elements] = sublist
my_list = seen_combos.values()
you could do it in a fairly straightforward way using dictionaries. but you'll need to use frozenset instead of set, as sets are mutable and therefore not hashable.
def _remove_duplicate_lists(duplicate_loop):
dupdict = OrderedDict((frozenset(x), x) for x in reversed(duplicate_loop))
return reversed(dupdict.values())
should do it. Note the double reversed() because normally the last item is the one that is preserved, where you want the first, and the double reverses accomplish that.
edit: correction, yes, per Steven's answer, it must be an OrderedDict(), or the values returned will not be correct. His version might be slightly faster too..
edit again: You need an ordered dict if the order of the lists is important. Say your list is
[[1,2,3,4], [4,3,2,1], [5,6,7,8]]
The ordered dict version will ALWAYS return
[[1,2,3,4], [5,6,7,8]]
However, the regular dict version may return the above, or may return
[[5,6,7,8], [1,2,3,4]]
If you don't care, a non-ordered dict version may be faster/use less memory.

Categories

Resources