my swap function is not working in python - 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]

Related

Slicing out a specific from a list

I have one list and I want to print out all elements of it but skip one specific.
a = [1,2,3,4,5,6,7,8,9]
I want to print out:
1,3,4,5,6,7,8,9
(in a column like a regular for-loop)
Is this possible?
Just slice on both sides and concatenate:
def skip_over(lst, i):
return lst[:i] + lst[i + 1:]
skip_over([1, 2, 3, 4, 5], 1) # [1, 3, 4, 5]
If you want to skip over all occurrences of a value, filter with a list comprehension:
def skip_all(lst, v):
return [x for x in lst if x != v]
skip_all([1, 2, 3, 2, 4, 5], 2) # [1, 3, 4, 5]
If you want to skip over the first occurrence of a value, then use index to get its index:
def skip_first(lst, v):
try:
i = lst.index(v)
except ValueError:
# value not in list so return whole thing
return lst
return lst[:i] + lst[i + 1:]
skip_first([1, 2, 3, 2, 4, 5], 2) # [1, 3, 2, 4, 5]
If you specify the element to be skipped by its position (index):
for position, element in enumerate(a):
if position != specified_position:
print(element)
If you specify the element to be skipped by its value:
for element in a:
if element != specified_value:
print(element)

How to return items in an iterable with an even index, in reverse

Make a function named reverse_evens that accepts a single iterable as an argument. Return every item in the iterable with an even index...in reverse.
def reverse_evens(item):
return item[::-2]
For example, with [1, 2, 3, 4, 5] as the input, the function would return [5, 3, 1].
This is two different operations:
Select the even-numbered indices
Reverse them
You can't do the first step backwards, since the index number is counted from the front.
def reverse_evens(item):
return item[::2][::-1]
One liner:
print([x for x in [1, 2, 3, 4, 5][::2][::-1]])
Or try this for a larger code:
def reverse_evens(item):
print(item)
a = []
for i in range(len(item)):
if i % 2 == 0:
a.append(item[i])
return reversed(a)
print([x for x in reverse_evens([1, 2, 3, 4, 5])])
Another way would be this (using list slicing):
def reverse_evens(item):
return item[-1::-2]
print(reverse_evens([1, 2, 3, 4, 5]))
Output:
[5, 3, 1]
The [-1:-2] means:
Start from the last element (that is why we use -1).
Count every two elements.

How to append to new list item when checking list with for loop?

I am having problems with this and can't figure out why my code is not working. Could someone help me out with this, please? I made this:
def f8(a_list, n):
"""
The parameter a_list is a list of int's. The parameter n is an int.
The function f8() should return a list that contains exactly one
of each number in a_list that occurs less than n times in a_list.
Example:
f8([1, 1, 7, 7, 7, 3, 3, 3, 4, 4, 4, 5, 5], 3) should return
[1, 5] (as 1 and 5 are the only numbers that occur less than 3
times in a_list)
"""
k = []
for i in a_list:
if i < a_list.count(n):
k.append(i)
return k
print f8([1, 7, 7, 3, 3, 3, 4, 4, 5], 2)
I would expect it should print [1,5], but it just gives me a None. Why is that? Could someone help me out, please? I am stuck here.
You have the counting the wrong way around! You need to count the occurrences of i and compare this against n. Also, you need to move the return outside the for-loop. Finally, to remove the repeats in the final list, we should iterate through set(a_list) so that we only iterate through unique elements. The neat thing about this is that since we are counting the occurrences in the original a_list, we don't need to create any copies or anything fiddly to deal with this.
This makes your function:
def f8(a_list, n):
k = []
for i in set(a_list):
if a_list.count(i) < n:
k.append(i)
return k
which works if we give it a test:
>>> f8([1, 1, 7, 7, 7, 3, 3, 3, 4, 4, 4, 5, 5], 3)
[1, 5]
>>> f8([1, 1, 2, 2, 2, 2, 4, 5, 6, 7, 7, 7, 7], 3)
[1, 4, 5, 6]
Note, if you wanted to shorten the function, you could achieve the same result in a one line list-comprehension:
def f8(a_list, n):
return [i for i in set(a_list) if a_list.count(i) < n]
which gives the same outputs to the tests as above.
Firstly, you should not call count repeatedly. Each call iterates the entire list. You can get all counts in one go using collections.Counter. Secondly, you need to check if you have added any element before to avoid duplicates, just calling set one a_list will not guarantee order of appearance:
from collections import Counter
def f8(a_list, n):
c = Counter(a_list)
k, seen = [], set()
for x in a_list:
if c[x] < n and x not in seen:
seen.add(x)
k.append(x)
return k
The condition to append in your code is never met, thus, no value is being returned. Instead, return after the loop is finished. Also, your counting condition is reversed, as you should be finding the count of i occurring in the list, not n:
k = []
for i in a_list:
if a_list.count(i) < n and i not in k:
k.append(i)
return k
The reason why you are receiving None is that the return statement does not pass, so to satisfy the variable storage during the function call, None is returned.

Use multiple functions at once on a list

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()).

Access deep list nested values by reference in Python

I have a list with nested lists and I want to create a function (modify_list) that gets a tuple and modifies the passed pointer with a passed value argument. The problem is that I'm not sure how to modify a nested value like this programmatically by reference.
Simplified example:
l = [[1, [2,3, [4,5,6]]]]
If I call the function modify_list, these would be how to use it and the expected results:
> l[0][1][2][2]
6
> modify_list((0, 1, 2, 2), 8)
> l
[[1, [2,3, [4,5,8]]]]
> modify_list((0, 1, 1), 14)
> l
[[1, [2,14, [4,5,8]]]]
Thanks
You can determine each sublist by accessing it with the respective index. Use the last index to assign the value:
def set_nested_val(l, indices, val):
for i in indices[:-1]:
l = l[i]
l[indices[-1]] = val
Note that this function operates on an arbitrary list (the first argument), and not only l. If you want to always modify l, use functools.partial:
import functools
l = [[1, [2,3, [4,5,6]]]]
modify_list = functools.partial(set_nested_val, l)
Note that nested lists, and accessing values by indicies, are often a sign of a bad data architecture. Have you considered a dict whose keys are tuples?
def modify_list(indices, new_value):
x = reduce(lambda x, i: x[i], indices[:-1], l)
x[indices[-1]] = new_value
Example:
>>> l = [[1, [2, 3, [4, 5, 6]]]]
>>> modify_list((0, 1, 2, 2), 8)
>>> l
[[1, [2, 3, [4, 5, 8]]]]
This method matches what you are asking for in your question, but it probably makes more sense to pass in the list that you want to mutate instead of always modifying the global variable:
def modify_list(lst, indices, new_value):
x = reduce(lambda x, i: x[i], indices[:-1], lst)
x[indices[-1]] = new_value
>>> l = [[1, [2, 3, [4, 5, 6]]]]
>>> modify_list(l, (0, 1, 2, 2), 8)
>>> l
[[1, [2, 3, [4, 5, 8]]]]
Try this:
def modify_list(lst, pos, val):
item = lst
while len(pos) > 1:
item = item[pos[0]]
pos = pos[1:]
item[pos[0]] = val
Or this:
def modify_list(lst, pos, val):
item = lst
for i in pos[:-1]:
item = item[i]
item[pos[-1]] = val
Or this:
def modify_list(lst, pos, val):
reduce(lambda a, e: a[e], pos[:-1], lst)[pos[-1]] = val
In any case, use it like this:
lst = [[1, [2, 3, [4, 5, 6]]]]
modify_list(lst, (0, 1, 2, 2), 8)
lst
> [[1, [2, 3, [4, 5, 8]]]]

Categories