Slicing out a specific from a list - python

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)

Related

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]

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.

python : group elements together in list

I'm currently working with itertools to create and return a list whose elements are lists that contain the consecutive runs of equal elements of the original list.
import itertools
it = [1, 1, 5, 5, 5, 'test', 'test', 5]
new = len(it)
for a in range(new):
return [list(k) for a, k in itertools.groupby(it)]
For the above example the result is:
[[1, 1], [5, 5, 5], ['test', 'test'], [5]]
Can I achieve this without using itertools?
You can pair adjacent items by zipping the list with itself but with a padding of float('nan') since it can't be equal to any object, and then iterate through the zipped pairs to append items to last sub-list of the output list, and add a new sub-list when the adjacent items are different:
output = []
for a, b in zip([float('nan')] + it, it):
if a != b:
output.append([])
output[-1].append(b)
output becomes:
[[1, 1], [5, 5, 5], ['test', 'test'], [5]]
To be honest a simple for loop could make this work, you don't even have to import itertools.
The simplest way to do this is by using this:
it = [1, 1, 5, 5, 5, 'test', 'test', 5]
result = []
for (i, x) in enumerate(it):
if i < 1 or type(x) != type(it[i - 1]) or x != it[i - 1]:
result.append([x])
else:
result[-1].append(x)
print(result)
Or, in function form:
def type_chunk(it):
result = []
for (i, x) in enumerate(it):
if i < 1 or type(x) != type(it[i - 1]) or x != it[i - 1]:
result.append([x])
else:
result[-1].append(x)
return result
You would then use the function like this:
print(type_chunk([1, 1, 5, 5, 5, 'test', 'test', 5]))
You could even skip the type checking and only look for equal values:
def type_chunk(it):
result = []
for (i, x) in enumerate(it):
if i < 1 or x != it[i - 1]:
result.append([x])
else:
result[-1].append(x)
return result
Good luck.
You could have a look at the function in itertools to see how they are doing it.
Here is one way which shows the logic clearly (can be further reduced):
def i_am_itertool():
it = [1, 1, 5, 5, 5, 'test', 'test', 5]
ret = []
temp = []
last = it[0]
for e in it:
if e == last:
temp.append(e)
else:
ret.append(temp) # Add previous group
temp = [e] # Start next group
last = e
ret.append(temp) # Add final group
return ret
print(i_am_itertool())
Output:
[[1, 1], [5, 5, 5], ['test', 'test'], [5]]

Find four numbers in a list that add up to a target value

Below is the code I wrote in an attempt to solve this problem: Find four numbers in a list that add up to x.
def sum_of_four(mylist, x):
twoSum = {i+j:[i,j] for i in mylist for j in mylist}
four = [twoSum[i]+twoSum[x-i] for i in twoSum if x-i in twoSum]
print four
sum_of_four([2, 4, 1, 1, 4, 6, 3, 8], 8)
The answer I get for the sample input is:
[[1, 1, 3, 3], [1, 2, 3, 2], [3, 1, 3, 1], [3, 2, 1, 2], [3, 3, 1, 1]]
However, this list of lists contains duplicates. For example, [1,1,3,3] is the same as [3,3,1,1].
How can I print the list of lists without duplicate lists? I want to be as efficient as possible in runtime and space. Is it possible to change my list comprehension so that I don't print duplicates? I certainly do not want to sort the lists and then use set() to delete duplicates. I want to do something better.
A correct and relatively efficient approach starts by counting the number of times each value occurs in the input list. Suppose value occurs count times. Then you can append up to count copies of value to a list in which you build a selection of values. Before appending any copies of value, and after appending each copy, make a recursive call to move on to the next value.
We can implement this approach as follows:
length = 4
# Requires that frequencies be a list of (value, count) sorted by value.
def doit(frequencies, index, selection, sum, target, selections):
if index == len(frequencies):
return
doit(frequencies, index + 1, selection[:], sum, target, selections) # Skip this value.
value, count = frequencies[index]
for i in range(count):
selection.append(value)
sum += value
if sum > target:
return # Quit early because all remaining values can only be bigger.
if len(selection) == length:
if sum == target:
selections.append(selection)
return # Quit because the selection can only get longer.
doit(frequencies, index + 1, selection[:], sum, target, selections) # Use these values.
def sum_of_length(values, target):
frequency = {}
for value in values:
frequency[value] = frequency.setdefault(value, 0) + 1
frequencies = sorted(frequency.items()) # Sorting allows for a more efficient search.
print('frequencies:', frequencies)
selections = []
doit(frequencies, 0, [], 0, target, selections)
return list(reversed(selections))
print(sum_of_length([2, 4, 1, 1, 4, 6, 3, 8], 8))
print(sum_of_length([1, 1, 1, 2, 2, 3, 3, 4], 8))
print(sum_of_length([-1, -1, 0, 0, 1, 1, 2, 2, 3, 4], 3))
By the way, the correct answer for your sample input is [[1, 1, 2, 4]]. There is only one way to select four elements from [2, 4, 1, 1, 4, 6, 3, 8] such that their sum is 8.
If you want to reuse the numbers more than once such as your sample answer where you only have one 3 in the list but you have [1,1,3,3] as a solution, then you can try:
def sum_of_four(list, x, y, curr=[]):
if y == 1:
for l in list:
if l == x:
d = curr[:]
d.append(l)
print(d)
break
else:
for i in range(len(list)):
l = list[i]
if l <= (x - l) / (y - 1):
d = curr[:]
d.append(l)
sum_of_four(list[i:], x-l, y-1, d)
sum_of_four(sorted([2,4,1,4,6,3,8]),8,4)

How to to split a list at a certain value

given a unique valued list such as [5,4,9,2,1,7,'dog',9] is there a way to split it a a certain value? ie
[5,4,9,2,7,'dog'].split(4)
= [5,4],[9,2,7,'dog']
[5,4,9,2,7,'dog'].split(2)
= [5,4,9,2], [7,'dog']
?
>>> mylist = [5,4,9,2,7,'dog']
>>> def list_split(l, element):
... if l[-1] == element:
... return l, []
... delimiter = l.index(element)+1
... return l[:delimiter], l[delimiter:]
...
>>> list_split(mylist, 4)
([5, 4], [9, 2, 7, 'dog'])
>>> list_split(mylist, 2)
([5, 4, 9, 2], [7, 'dog'])
>>> list_split(mylist, 'dog')
([5, 4, 9, 2, 7, 'dog'], [])
Here is a function that will split a list into an arbitrary number of sub-lists and return a list of them, much like a string split.
def split_list(input_list,seperator):
outer = []
inner = []
for elem in input_list:
if elem == separator:
if inner:
outer.append(inner)
inner = []
else:
inner.append(elem)
if inner:
outer.append(inner)
return outer
>>> split_list([1,2,3,4,1,2,3,4,4,3,4,3],3)
[[1, 2], [4, 1, 2], [4, 4], [4]]
If the separator element is to be retained on the sub-list to the left, as specifically posed in the question, then this variation will do it:
def split_list(input_list,seperator):
outer = []
inner = []
for elem in input_list:
if elem == separator:
inner.append(elem)
outer.append(inner)
inner = []
else:
inner.append(elem)
if inner:
outer.append(inner)
return outer
>>> splitlist.split_list([1,2,3,4,1,2,3,4,4,3,4,3],3)
[[1, 2, 3], [4, 1, 2, 3], [4, 4, 3], [4, 3]]
def listsplit(l, e):
try:
i = l.index(e) + 1
return l[:i], l[i:]
except ValueError:
return l
In the case of the element being at the first or last index in the list, one of the returned lists will be empty, but I'm not entirely sure if this is a problem. In the case of ValueError from the list.index call, you'll have only the list itself returned, but if another behavior is desired, it's pretty simple to change.
Not as such, but you can pretty easily slice the list you're making using the index method and get the results you show in your example output.
>>> l1 = [5, 4, 9, 2, 7, 'dog']
>>> l1[:l1.index(4) + 1], l1[l1.index(4) + 1:]
([5, 4], [9, 2, 7, 'dog'])
The '+1' is there because you wanted the needle (4) to appear in the first list.
Note that this splits on the first occurrence, which is pretty typical. If you really want a split method as in your question, you can subclass list and write your own using something like this.
On one line:
[x[k+1:x[k+1:len(x)].index(4)+len(x[:k+1])] for k in [c for c in [-1]+[i for i, a in enumerate(x) if a == 4]][:-1] ] + [x[(len(x) - 1) - x[::-1].index(4)+1:len(x)]]
The function:
def split_list(x, value):
return [x[k+1:x[k+1:len(x)].index(value)+len(x[:k+1])] for k in [c for c in [-1]+[i for i, a in enumerate(x) if a == value]][:-1] ] + [x[(len(x) - 1) - x[::-1].index(value)+1:len(x)]]
It will work in case the separator exists several times, and in cas it exists at thy end or the beginning of the lis.
Details:
Part 1: [c for c in [-1]+[i for i, a in enumerate(x) if a == value]][:-1]
Get the indexes of occurences of value, append "-1" in the beginning and remove the index of the last occurence.
x[k+1:x[k+1:len(x)].index(value)+len(x[:k+1])]
Make a slice (let's callet Slice A) of the list starting the first time from 0 (that's why I appended [-1] -1+1=0) and then starting from occurence index +1 (to make the current occurence unreachable) with each occurence index got from Part 1, then I take another slice starting from the curent occurence index +1 ending at thy end of the list, then I look for the first occurence in this slice, I get it; because it was a slice, I add the current offset (the part from beginning + current occurence index +1) to it, at this point I get the position to stop in, this is the end of the slice A. I finally obtain a split section each time.
I removed the index of the last occurence, coz it is not relevant to calculate anything after that index, so I just apend them at thy end: + [x[(len(x) - 1) - x[::-1].index(value)+1:len(x)]]
Use slicing:
def split_list(li, item):
if item not in li:
return li
else:
return [li[0:li.index(item)+1], li[li.index(item)+1:]]
Testing:
for item in (5,4,2,'dog'):
print item, split_list([5,4,9,2,7,'dog'], item)
Prints:
5 [[5], [4, 9, 2, 7, 'dog']]
4 [[5, 4], [9, 2, 7, 'dog']]
2 [[5, 4, 9, 2], [7, 'dog']]
dog [[5, 4, 9, 2, 7, 'dog'], []]

Categories