Related
I am new to python and so I am experimenting a little bit, but I have a little problem now.
I have a list of n numbers and I want to make a new list that contains only every second pair of the numbers.
So basically if I have list like this
oldlist = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
then I want that the new list looks like this
newlist = [3, 4, 7, 8]
I already tried the slice() function, but I didn't find any way to make it slice my list into pairs. Then I thought that I could use two slice() functions that goes by four and are moved by one, but if I merge these two new lists they won't be in the right order.
If you enumerate the list, you'd be taking those entries whose indices give either 2 or 3 as a remainder when divided by 4:
>>> [val for j, val in enumerate(old_list) if j % 4 in (2, 3)]
[3, 4, 7, 8]
a = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
b = [a[i] for i in range(len(a)) if i%4 in (2,3)]
# Output: b = [3, 4, 7, 8]
Here, we use the idea that the 3rd,4th,7th,8th..and so on. indices leave either 2 or 3 as the remainder when divided by 4.
first_part = oldList[2::4] # every 4th item, starting from the 3rd item
second_part = oldList[3::4] # every 4th item starting from the 4th item
pairs = zip(first_part, second_part)
final_result = chain.from_iterable(pairs)
Break this problem in to parts.
first = oldlist[2::4]
second = oldlist[3::4]
pairs = [(x, y) for x, y in zip(first, second)]
Now unwrap the pairs:
newlist = [x for p in pairs for x in p]
Combining:
newlist = [z for p in [(x, y) for x, y in zip(oldlist[2::4], oldlist[3::4])] for z in p]
I would firstly divide original list into two lists, with odd and even elements. Then iterate over zip of them.
old = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
result = list()
part1, part2 = old[::2], old[1::2]
for i, z in enumerate(zip(part1,part2)):
if i % 2 == 0:
result.extend(z)
You could use a double range:
oldlist = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
newlist = []
for i,j in zip(range(2, len(oldlist), 4), range(3, len(oldlist), 4)):
newlist += [oldlist[i], oldlist[j]]
#> newlist: [3, 4, 7, 8]
import more_itertools
oldlist = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
[*more_itertools.interleave(oldlist[2::4], oldlist[3::4])]
# [3, 4, 7, 8]
oldlist[2::4], oldlist[3::4]: slice 4th item
[*more_itertools.interleave(...)]: interleave the two above and convert back to a list
Here is what I have come up with:
oldList = list(range(1,10))
newList = []
for i in oldList:
if (i%2 == 0) and (i%4 != 0):
try:
newList.append(i+1)
newList.append(i+2)
except IndexError:
break
Result:
>>> newList
[3, 4, 7, 8]
I want to duplicate an specific element as many times as indicated.
The original list would look like this:
list=[1,2,3,4,5,6,7,8,9]
And here would have to be the duplicator and the element of the list that we want to duplicate.
times=4
num=4
The final list would have to look like this:
list=[1,2,3,4,4,4,4,5,6,7,8,9]
There are many ways to do it and if your list only have one occurrence of the number this is likely the simplest way
lst = [1,2,3,4,5,6,7,8,9]
num = 4
times = 4
ix = lst.index(num)
lst[ix:ix+1] = [num] * times
You can simply use list repetition and concatenation:
lst = [1, 2, 3, 4, 5, 6, 7, 8, 9]
times = 4
num = 4
ind = lst.index(num)
result = lst[:ind] + [num] * times + lst[ind + 1:]
print(result)
[1, 2, 3, 4, 4, 4, 4, 5, 6, 7, 8, 9]
You can try with this:
ex_list = [1,2,3,4,5,6,7,8,9]
times=4
num=4
new_list = sorted(ex_list + [ex_list[ex_list.index(times)]] * (num-1))
print(new_list)
Output:
[1, 2, 3, 4, 4, 4, 4, 5, 6, 7, 8, 9]
I need to slice a list using python 3.7, and slice should contains two elements, if at the end we got one elements (like below), that's last element should go to previous part.
def solution(A):
l = len(A)
size = 2
for i in range(1, len(A), size):
print(A[i:i+2])
solution([4,2,2,5,1,5,8,9])
Output:
[2, 2]
[5, 1]
[5, 8]
[9]
Desire output:
[2, 2]
[5, 1]
[5, 8, 9]
Thanks for your help
def solution(A):
l = len(A)
size = 2
groups = [ A[i:i+size] for i in range(1, len(A), size) ]
if len(groups[-1]) < size:
groups[-2].extend(groups.pop())
for x in groups:
print(x)
Works for every value of size, not just 2.
You could just check if the next loop iteration will go too far, and if so print the entire list and stop.
Like so
def solution(A):
l = len(A)
size = 2
for i in range(1, len(A), size):
print(i)
if i+2*size > len(A):
print(A[i:])
break
else:
print(A[i:i+2])
def solution(A):
l = len(A)
size = 2
for i in range(0, len(A), size):
if l%2!=1 and i==l-3: #if the length is odd and i is the third last
print(A[i:i+3])
break
else:
print(A[i:i+2])
solution([4,2,2,5,1,5,8,9])
This function will do the trick (I'm not very happy with it, and I'm sure that there must be a better way out there, but it will do for now).
def listSlicing(raw_list, slice_length):
# Get the number of elements that will be left out when the list is sliced
extra_elements = len(raw_list)%slice_length
# Create a list of slices. Do not go to the last element
sliced_list = [raw_list[i:i+slice_length] for i in range(0, len(raw_list)-extra_elements, slice_length)]
# Access the last item of the sliced list and append the extra elements to it
if extra_elements == 0:
return sliced_list # No need to change the last value
else:
sliced_list[-1].extend(raw_list[-extra_elements:])
return sliced_list
l = [4,2,2,5,1,5,8,9,10]
listSlicing(l, 2)
# Will return [[4, 2], [2, 5], [1, 5], [8, 9, 10]]
In case there is only space for one slice (for example, assume a slice_length of 5 instead of 2), the function will return only a single list, as, after creating the first slice, the remaining 4 items (5, 8, 9, 10) will be appended to the first slice itself, effectively returning the same list again.
def func(a, size):
c=[]
if size==0 or size<0:
return []
if size>=len(a):
return a
c = [a[i:i+size] for i in range(0,(len(a)//size)*size,size) if i%size==0]
c[-1].extend(a[(len(a)//size)*size:])
return c
a = [4,2,2,5,1,5,8,9, 10]
print(func(a, 2))
print(func(a, 111))
print(func(a, 9))
print(func(a, 5))
output
[[4, 2], [2, 5], [1, 5], [8, 9, 10]]
[4, 2, 2, 5, 1, 5, 8, 9, 10]
[4, 2, 2, 5, 1, 5, 8, 9, 10]
[[4, 2, 2, 5, 1, 5, 8, 9, 10]]
I need to remove the duplicate occurrence of the 1st element in the list which is duplicate (present more than once) while preserving the order of the input list. For eg: for the input of
in = [2, 3, 4, 5, 3, 6, 4, 1]
output should be
out = [2, 3, 4, 5, 6, 4, 1]
I have tried below and is giving correct result , I just wanted to check with the community if there is a better or more pythonic solution to this
input = [2, 3, 4, 5, 3, 6, 4, 1]
first_dupe = None
for elem in input:
if input.count(elem) > 1:
first_dupe = elem
break
flg = True
new_list = []
for x in input:
if x != first_dupe or flg is True:
new_list.append(x)
if x == first_dupe:
flg = False
print(new_list)
If you just want to remove the first duplicate, you can create set, append elements to a new list if they are in the set while removing each element from the set as well. When an element is not seen, append the rest of the list.
This is fairly efficient if the duplicate is seen early, but has O(1) if the element is seen late.
x = [2, 3, 4, 5, 3, 6, 4, 1]
s = set(x)
out = []
for i,z in enumerate(x):
if z in s:
out.append(z)
s.remove(z)
else:
break
out += x[i+1:]
out
# returns:
[2, 3, 4, 5, 6, 4, 1]
You could keep track of what you have already used and check if the value is in there.
lst = [2, 3, 4, 5, 3, 6, 4, 1]
used = set([])
for i, x in enumerate(lst):
if x in used:
lst.pop(i)
break
used.add(x)
print(lst)
Also, don't give variables, or anything else, the same name as a keyword in python. input is already a built-in function.
This is my version of Chiheb Nexus' answer.
def find_dup(lst):
seen = set()
it = iter(lst)
for item in it:
if item not in seen:
seen.add(item)
yield item
else:
yield from it
lst = [2, 3, 4, 5, 3, 6, 4, 1]
list(find_dup(lst))
[2, 3, 4, 5, 6, 4, 1]
Title is definitely confusing, so here's an example: Say I have a list of values [1,2,3,2,1,4,5,6,7,8]. I want to remove between the two 1s in the list, and by pythonic ways it will also end up removing the first 1 and output [1,4,5,6,7,8]. Unfortunately, due to my lack of pythonic ability, I have only been able to produce something that removes the first set:
a = [1,2,3,2,1,4,5,6,7]
uniques = []
junks = []
for value in a:
junks.append(value)
if value not in uniques:
uniques.append(value)
for value in uniques:
junks.remove(value)
for value in junks:
a.remove(value)
a.remove(value)
a[0] = 1
print(a)
[1,4,5,6,7]
Works with the first double occurrence and will not work with the next occurrence in a larger list. I have an idea which is to remove between the index of the first occurrence and the second occurrence which will preserve the second and not have me do some dumb thing like a[0] = 1 but I'm really not sure how to implement it.
Would this do what you asked:
a = [1, 2, 3, 2, 1, 4, 5, 6, 7, 8]
def f(l):
x = l.copy()
for i in l:
if x.count(i) > 1:
first_index = x.index(i)
second_index = x.index(i, first_index + 1)
x = x[:first_index] + x[second_index:]
return x
So the output of f(a) would be [1, 4, 5, 6, 7, 8] and the output of f([1, 2, 3, 2, 1, 4, 5, 6, 7, 8, 7, 6, 5, 15, 16]) would be [1, 4, 5, 15, 16].
if you want to find unique elements you can use set and list
mylist = list(set(mylist))
a = [1, 2, 3, 2, 1, 4, 5, 6, 7, 8, 7, 6, 5, 15, 16]
dup = [x for x in a if a.count(x) > 1] # list of duplicates
while dup:
pos1 = a.index(dup[0])
pos2 = a.index(dup[0], pos1+1)
a = a[:pos1]+a[pos2:]
dup = [x for x in a if a.count(x) > 1]
print a #[1, 4, 5, 15, 16]
A more efficient solution would be
a = [1, 2, 3, 2, 1, 4, 5, 6, 7, 8, 7, 6, 5, 15, 16]
pos1 = 0
while pos1 < len(a):
if a[pos1] in a[pos1+1:]:
pos2 = a.index(a[pos1], pos1+1)
a = a[:pos1]+a[pos2:]
pos1 += 1
print a #[1, 4, 5, 15, 16]
(This probably isn't the most efficient way, but hopefully it helps)
Couldn't you just check if something appears twice, if it does you have firstIndex, secondIndex, then:
a=[1,2,3,4,5,1,7,8,9]
b=[]
#do a method to get the first and second index of the repeated number then
for index in range(0, len(a)):
print index
if index>firstIndex and index<secondIndex:
print "We removed: "+ str(a[index])
else:
b.append(a[index])
print b
The output is [1,1,7,8,9] which seems to be what you want.
To do the job you need:
the first and the last position of duplicated values
all indexes between, to remove them
Funny thing is, you can simply tell python to do this:
# we can use a 'smart' dictionary, that can construct default value:
from collections import defaultdict
# and 'chain' to flatten lists (ranges)
from itertools import chain
a = [1, 2, 3, 2, 1, 4, 5, 6, 7]
# build dictionary where each number is key, and value is list of positions:
index = defaultdict(list)
for i, item in enumerate(a):
index[item].append(i)
# let's take first only and last index for non-single values
edges = ((pos[0], pos[-1]) for pos in index.values() if len(pos) > 1)
# we can use range() to get us all index positions in-between
# ...use chain.from_iterable to flatten our list
# ...and make set of it for faster lookup:
to_remove = set(chain.from_iterable(range(start, end)
for start, end in edges))
result = [item for i, item in enumerate(a) if i not in to_remove]
# expected: [1, 4, 5, 6, 7]
print result
Of course you can make it shorter:
index = defaultdict(list)
for i, item in enumerate([1, 2, 3, 2, 1, 4, 5, 6, 7]):
index[item].append(i)
to_remove = set(chain.from_iterable(range(pos[0], pos[-1])
for pos in index.values() if len(pos) > 1))
print [item for i, item in enumerate(a) if i not in to_remove]
This solution has linear complexity and should be pretty fast. The cost is
additional memory for dictionary and set, so you should be careful for huge data sets. But if you have a lot of data, other solutions that use lst.index will choke anyway, because they are O(n^2) with a lot of dereferencing and function calls.