Use multiple functions at once on a list - python

Basically, I have a list and I want to perform multiple functions on it at once. For example,
List = [1,2,3,4,5]
List.extend([1,2,3,4,5]).sort().reverse()
I would like the result to be [5,5,4,4,3,3,2,2,1,1].
I haven't used Python in a while, but I know I've done something like this before. Is it something simple I'm missing or what?
It has to all be on one line by the way.

Most Python methods that mutate a container in-place return None
However your example can easily be handled in one line
L = [1,2,3,4,5]
L = sorted(L+[1,2,3,4,5], reverse=True)
Keeping in the spirit of the challenge, it's not hard to chain the operations (because they always return None)
>>> L = [1, 2, 3, 4, 5]
>>> L.extend([1,2,3,4,5]) or L.sort() or L.reverse() or L
[5, 5, 4, 4, 3, 3, 2, 2, 1, 1]
Here's another way
>>> L = [1, 2, 3, 4, 5]
>>> (L.extend([1,2,3,4,5]), L.sort(), L.reverse()) and L
[5, 5, 4, 4, 3, 3, 2, 2, 1, 1]
And you can let your imagination run wild
>>> L = [1, 2, 3, 4, 5]
>>> max(L.extend([1,2,3,4,5]), L.sort(), L.reverse(), L) # Python2.x only
[5, 5, 4, 4, 3, 3, 2, 2, 1, 1]

You cannot chain the above operations since they are performed in-place.
As alternatives, use sorted() and reversed().

How about:
>>> l = [1,2,3,4,5]*2
>>> l.sort(reverse=True)
>>> l
[5, 5, 4, 4, 3, 3, 2, 2, 1, 1]
Or even shorter:
>>> sorted([1,2,3,4,5]*2,reverse=True)
[5, 5, 4, 4, 3, 3, 2, 2, 1, 1]

Each of those functions acts on the list in-place, returning None and not the modified list. You'd have to do something like
l = [1,2,3,4,5]
l = reversed(sorted(l + [1,2,3,4,5]))

Not perfect but interesting..
class chain():
def __init__(self, my_object):
self.o = my_object
def __getattr__(self, attr):
x = getattr(self.o, attr)
if hasattr(x, '__call__'):
method = x
return lambda *args: self if method(*args) is None else method(*args)
else:
prop = x
return prop
list_ = chain([1, 2, 3, 0])
print list_.extend([9,5]).sort().reverse()

The functions extend, sort and reverse doesn't return list but change the list on which they are called. Chaining relies on a fact that previous function returns some value and works on it.
E.g. s="abc" then you can do s.upper().lower() as .upper() return a new string in uppercase (ans same for .lower()).

Related

Recursion with list but I got some [..]

I tried to create a problem like [0,1,2,[0,1,2,[0,1,2,[0,1,2] ] ]... by using recursion it but it got some bugs that I don't know where it came from.
It creates an output like this:
[1, 2, 3, 4, 5, [...]]
So let's make an example x = [1,2,3,4,5] and len_ = len(x) for the recursion. The code will be like this:
list_ = [1,2,3,4,5]
n = len(list_)
dull = []
def BlastedField3(n):
global list_
list_ += [list_]
if n == 1:
return list_
if n > 1:
return list_
return BlastedFild(n-1)
print(BlastedField3(n))
So I was imagining that list_ += [list_] was something like per each recursion of the function the list_ += [list_] working too.But! it works but the bug [...] is coming up next to it.
Is there a way to solve this without this bug [...] or just try a loop?
The problem of creating a self-containing list can be solved by not using references but shallow copies and by not reusing global variables (whenever you feel the need for those, look at your design long and hard).
base = [1,2,3,4,5]
def blasted(n):
if n <= 1:
return base[:] # shallow copy to never accidentally expose your base
return base + [blasted(n-1)]
>>> blasted(1)
[1, 2, 3, 4, 5]
>>> blasted(2)
[1, 2, 3, 4, 5, [1, 2, 3, 4, 5]]
>>> blasted(3)
[1, 2, 3, 4, 5, [1, 2, 3, 4, 5, [1, 2, 3, 4, 5]]]
Actually the use of shallow copies is not strictly necessary as the code never mutates the base list. But I would still recommend it because if someone were to mutate any result of the blast, base might be affected.

my swap function is not working in python

please guys, this function is meant to swap a group of items in a list, like the first k items with the last k items, but I dont know how to get the function to work
def swap(L, k):
L[len(L)-k:], L[:k] = L[:k], L[len(L)-k:]
yet when I run this with doctest, it fails
swap([1, 2, 3, 4, 5, 6],2)
Fix the indexes, return a list from the method, and print the resulting list:
def swap(L, k):
return L[(-k):] + L[k:(-k)] + L[:k]
lst = swap([1, 2, 3, 4, 5, 6], 2)
print(lst)
# [5, 6, 3, 4, 1, 2]
Note that the original list is not modified - what is returned is a different list with elements swapped.
The function works perfectly, but you have no other references to the list you're passing in, so it gets discarded. Simply save the list to a name before passing it in.
By the way, the len(L) is unnecessary.
def swap(L, k):
"""
>>> lst = [1, 2, 3, 4, 5, 6]
>>> swap(lst, 2)
>>> lst
[5, 6, 3, 4, 1, 2]
"""
L[-k:], L[:k] = L[:k], L[-k:]
def swap(L, k):
J = L[:k]
L[:k] = L[-2:]
L[-2:] = J
P = [1,2,3,4,5,6]
swap(P,2)
# P ==[5, 6, 3, 4, 1, 2]

Why does `mylist[:] = reversed(mylist)` work?

The following reverses a list "in-place" and works in Python 2 and 3:
>>> mylist = [1, 2, 3, 4, 5]
>>> mylist[:] = reversed(mylist)
>>> mylist
[5, 4, 3, 2, 1]
Why/how? Since reversed gives me an iterator and doesn't copy the list beforehand, and since [:]= replaces "in-place", I am surprised. And the following, also using reversed, breaks as expected:
>>> mylist = [1, 2, 3, 4, 5]
>>> for i, item in enumerate(reversed(mylist)):
mylist[i] = item
>>> mylist
[5, 4, 3, 4, 5]
Why doesn't the [:] = fail like that?
And yes, I do know mylist.reverse().
CPython list slice assigment will convert the iterable to a list first by calling PySequence_Fast. Source: https://hg.python.org/cpython/file/7556df35b913/Objects/listobject.c#l611
v_as_SF = PySequence_Fast(v, "can only assign an iterable");
Even PyPy does something similar:
def setslice__List_ANY_ANY_ANY(space, w_list, w_start, w_stop, w_iterable):
length = w_list.length()
start, stop = normalize_simple_slice(space, length, w_start, w_stop)
sequence_w = space.listview(w_iterable)
w_other = W_ListObject(space, sequence_w)
w_list.setslice(start, 1, stop-start, w_other)
Here space.listview will call ObjSpace.unpackiterable to unpack the iterable which in turn returns a list.

Python, RHS of assignment is "None" (this isn't expected) [duplicate]

The methods append and extend in Python are not functional by nature, they modify the callee and return None.
Is there an alternative way to do what these methods do and get a new list as a returned value?
Consider this example:
def myfun(first, *args):
for elem in [first].extend(args):
print elem
Obviously, this won't work.
Is there a way to construct a new list directly with an expression, instead of being forced to write the following?
def myfun(first, *args):
all_args = list(first)
all_args.extend(args)
for elem in all_args:
print elem
Thanks.
>>> def append(lst, elem):
... return lst + [elem]
...
>>> append([1, 2, 3], 4)
[1, 2, 3, 4]
>>> def extend(lst1, lst2):
... return lst1 + lst2
...
>>> extend([1, 2], [3, 4])
[1, 2, 3, 4]
Is that what you wanted?
You may also define your own type, which returns the list itself on these operations, in addition to change:
>>> class MyList(list):
... def append(self, x):
... super(MyList, self).append(x)
... return self
... def extend(self, lst):
... super(MyList, self).extend(lst)
... return self
...
>>> l = MyList([1, 2, 3])
>>> l.append(4)
[1, 2, 3, 4]
>>> l.extend([5, 6, 7])
[1, 2, 3, 4, 5, 6, 7]
>>> l
[1, 2, 3, 4, 5, 6, 7]
You can rewrite that as:
[first] + args

Is there a way to init a list without using square bracket in Python?

Is there a way to init a list without using square bracket in Python?
For example, is there a function like list_cons so that:
x = list_cons(1, 2, 3, 4)
is equivalent to:
x = [1, 2, 3, 4]
In [1]: def list_cons(*args):
...: return list(args)
...:
In [2]: list_cons(1,2,3,4)
Out[2]: [1, 2, 3, 4]
Use the list constructor and pass it a tuple.
x = list((1,2,3,4))
I don't think that would be a particularly useful function. Is typing brackets so hard? Perhaps we could give you a more useful answer if you explained why you want this.
Still, here's a fun thing you can do in Python 3:
>>> (*x,) = 1, 2, 3, 4, 5
>>> x
[1, 2, 3, 4, 5]
You can even omit the parenthesis -- *x, = 1, 2, 3, 4, 5 works too.
works only in python 2.x:
>>> def list_cons(*args):
return map(None,args)
>>> list_cons(1,2,3,4)
[1, 2, 3, 4]

Categories