This is a very simple expression, but I have no idea how it operates.
print(sum([[3], [5]], []))
# returns [3,5]
why on earth does sum([[3], [5]], []) return [3,5]? My knowledge on sum() is that it takes in an iterable and sums the elements in the iterable. So usually the elements are integers.
For example, I'm familiar with something like:
sum([1,2,3])
# returns 6
But sum([[3], [5]], []) has two inputs, one a list of lists, and another an empty list. I thought this would return an error, but surprisingly it returned the above result. I haven't seen something like this before, and I would appreciate it if anyone could tell me the operations going on for this example.
sum() takes two parameters :
the iterable (here [[3],[5]])
the start, which has a default value of 0 (an int)
When you use
sum([[3],[5]])
start has the default value 0, so the function tries to add [3] and [5] to 0, an int, so you have TypeError.
On the other hand, when you use
sum([[3],[5]],[])
with [] as start value, [] + [3] + [5], it first instantiates an empty list before adding list-type elements to it.
This sum is correct with output [3,5]
This is equivalent to:
s = []
for lst in [[3], [5]]:
s += lst
You need to know that the list can be connected through the operator +,even if it contains an empty list, it will get a copy of another list.
About why sum ([[3], [5]]) raise error, see the signature of sum function:
sum(iterable, start)
If you don't specify start, the default value seems to be 0, which of course cannot be added to the list.
Related
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
I've had a look through the forums and can't find anything to do with multiplying all elements in an array recursively.
I've created the following code that almost does what I want. The goal is to use no loops and only recursion.
Here's the code:
def multAll(k,A):
multAllAux(k,A)
return A[:]
def multAllAux(k,A):
B = [0]
if A == []:
return 0
else:
B[0] = (A[0] * k)
B.append(multAllAux(k,A[1:]))
return B
print(multAllAux(10, [5,12,31,7,25] ))
The current output is:
[50, [120, [310, [70, [250, 0]]]]]
However, it should be:
[50,120,310,70,250]
I know I am close, but I am at a complete loss at this point. The restrictions of no loops and solely recursion has left me boggled!
Your multAllAux function returns a list. If you append a list to another list, you get this nested list kind of structure that you are getting right now.
If you instead use the "extend" function; it will work as expected.
>>> a = [1, 2, 3]
>>> a.extend([4, 5])
>>> a
[1, 2, 3, 4, 5]
extend takes the elements from a second list and adds them to the first list, instead of adding the second list itself which is what append does!
Your function also returns a zero at the end of the list, which you don't need. You can try this:
def mult(k, A: list) -> list:
return [k * A[0]] + mult(k, A[1:]) if A else []
The problem is here:
B.append(multAllAux(k,A[1:])))
What .append(..) does is it takes the argument, considers it as a single element and adds that element to the end of the list. What you want is to concatenate to the list (ie the item being added should be seen as a list of elements rather than one single element).
You can say something like: B = B + multAllAux(..) or just use +=
B += multAllAux(...)
BTW, if you wanted to multiply a single number to a list, there is a very similar construct: map(..). Note that this behaves slightly differently depending on whether you're using Py2 or Py3.
print(map(lambda x: x * 10, [5,12,31,7,25]))
In a piece of code I need to copy a list and append a new value. I have found the following behaviour:
a=[]
b=[n for n in a].append('val')
print(b)
None
While, the following works as I require:
b=[n for n in a]
b.append('val')
print(b)
['val']
Any insight why it is so?
append modifies the list in place, it doesn't return a new list, that's why you're getting None.
See the documentation:
.. The methods that add, subtract, or rearrange their members in place, and don’t return a specific item, never return the collection instance itself but None.
Method append returns None, because it modifies list in place, that is why b in your first example is None. You could use list concatenation in order to copy a list and append an element to it:
In [238]: a = [1, 2, 3]
In [239]: b = a + [4]
In [240]: b
Out[240]: [1, 2, 3, 4]
That is because b=[n for n in a].append('val') does not return anything. In specific append('val') does not return any value.
I know that the list() constructor creates a new list but what exactly are its characteristics?
What happens when you call list((1,2,3,4,[5,6,7,8],9))?
What happens when you call list([[[2,3,4]]])?
What happens when you call list([[1,2,3],[4,5,6]])?
From what I can tell, calling the constructor list removes the most outer braces (tuple or list) and replaces them with []. Is this true? What other nuances does list() have?
list() converts the iterable passed to it to a list. If the itertable is already a list then a shallow copy is returned, i.e only the outermost container is new rest of the objects are still the same.
>>> t = (1,2,3,4,[5,6,7,8],9)
>>> lst = list(t)
>>> lst[4] is t[4] #outermost container is now a list() but inner items are still same.
True
>>> lst1 = [[[2,3,4]]]
>>> id(lst1)
140270501696936
>>> lst2 = list(lst1)
>>> id(lst2)
140270478302096
>>> lst1[0] is lst2[0]
True
Python has a well-established documentation set for every release version, readable at https://docs.python.org/. The documentation for list() states that list() is merely a way of constructing a list object, of which these are the listed ways:
Using a pair of square brackets to denote the empty list: []
Using square brackets, separating items with commas: [a], [a, b, c]
Using a list comprehension: [x for x in iterable]
Using the type constructor: list() or list(iterable)
The list() function accepts any iterable as its argument, and the return value is a list object.
Further reading: https://docs.python.org/3.4/library/stdtypes.html#typesseq-list
Yes it is true.
Its very simple. list() takes an iterable object as input and adds its elements to a newly created list. Elements can be anything. It can also be an another list or an iterable object, and it will be added to the new list as it is.
i.e no nested processing will happen.
You said: "From what I can tell, calling the constructor list removes the most outer braces (tuple or list) and replaces them with []. Is this true?"
IMHO, this is not a good way to think about what list() does. True, square brackets [] are used to write a list literal, and are used when you tell a list to represent itself as a string, but ultimately, that's just notation. It's better to think of a Python list as a particular kind of container object with certain properties, eg it's ordered, indexable, iterable, mutable, etc.
Thinking of the list() constructor in terms of it performing a transformation on the kind of brackets of a tuple that you pass it is a bit like saying adding 3 to 6 turns the 6 upside down to make 9. It's true that a '9' glyph looks like a '6' glyph turned upside down, but that's got nothing to do with what happens on the arithmetic level, and it's not even true of all fonts.
aTuple = (123, 'xyz', 'zara', 'abc');
aList = list(aTuple)
print "List elements : ", aList
When we run above program, it produces following result:
List elements : [123, 'xyz', 'zara', 'abc']
It is another way to create a list in python. How convenient!
Your question is vague, but this is the output as follows, it doesn't "replace" the outer braces, it creates a data structure of a list, that can contain any value in a "listed" order (one after the other, after the other, and so on...) in a recursive way, you can add/remove elements to a specified index using append and pop. By the other hand, tuples are static and are not dynamically linked, they are more like an array of any type of element.
WHEN:
list((1,2,3,4,[5,6,7,8],9))
RETURNS:
[1, 2, 3, 4, [5, 6, 7, 8], 9]
WHEN:
list([[[2,3,4]]])
RETURNS:
[[[2, 3, 4]]]
WHEN:
list([[1,2,3],[4,5,6]])
RETURNS:
[[1, 2, 3], [4, 5, 6]]
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.