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 store even number and odd number in a separate list. But, here I am facing a unique problem. I am able to store it in sets but not in lists. Is there a way wherein I can store these in a List without repetition.
I have tried this in Jupyter notebook
list_loop=[1,2,3,4,5,6,7,8,9,10,11,12,13,1,4,1,51,6,17,]
for i in list_loop:
if i % 2 == 0 :
list_even = list_even + [i]
else:
list_odd = list_odd + [i]
print(set(list_even))
print(set(list_odd))
Expected output:
[2,4,6,8,10,12]
[1,3,5,7,9,11,13,17,51]
Define list_odd and list_even as lists and don't convert them to sets before printing. Note that you can use list comprehension to fill list_odd and list_even:
list_odd = []
list_even = []
list_loop=[1,2,3,4,5,6,7,8,9,10,11,12,13,1,4,1,51,6,17,]
list_odd = [elem for elem in list_loop if elem % 2 != 0]
list_even = [elem for elem in list_loop if elem % 2 == 0]
print(list_even)
print(list_odd)
Output:
[2, 4, 6, 8, 10, 12, 4, 6]
[1, 3, 5, 7, 9, 11, 13, 1, 1, 51, 17]
Edit: for uniqueness, turn list_loop into a set:
list_loop=set([1,2,3,4,5,6,7,8,9,10,11,12,13,1,4,1,51,6,17,])
Output:
[2, 4, 6, 8, 10, 12]
[1, 3, 5, 7, 9, 11, 13, 17, 51]
Use a comprehension
>>> list_loop=[1,2,3,4,5,6,7,8,9,10,11,12,13,1,4,1,51,6,17,]
>>> print(list(set(_ for _ in list_loop if _ % 2)))
[1, 3, 5, 7, 9, 11, 13, 17, 51]
Similarly for even numbers.
There are a couple of ways you could do this. You could use the OrderedDict in the collections library, or you could just sort the set and get a list,
...
print(sorted(set(list_even)))
print(sorted(set(list_odd)))
Also, I would personally create those lists using a set comprehension
list_even = sorted({x for x in list_loop if x % 2 == 0})
list_odd = sorted({x for x in list_loop if x % 2 == 1})
You can solve this using a list comprehension with a filter condition - but you then iterate your list twice.
By using a simple for loop you only need to touch any number once at it will conserve the original order - what putting your numbers through a set might not do - order in a set is not guaranteed:
Keep a set of seen numbers, only add anything if your current number was not yet seen.
list_loop = [1,2,3,4,5,6,7,8,9,10,11,12,13,1,4,1,51,6,17,]
list_even = []
list_odd = []
seen = set()
trick = [list_even, list_odd] # even list is at index 0, odd list at index 1
for i in list_loop:
if i in seen:
continue
else:
seen.add(i)
# the trick eliminates the need for an if-clause
trick[i%2].append(i) # you use i%2 to get either the even or odd index
print(list_even)
print(list_odd)
Output:
[2, 4, 6, 8, 10, 12]
[1, 3, 5, 7, 9, 11, 13, 51, 17]
You can apply the list function to your set object in order to
convert it to a list.
list_from_set = list(set(list_even))
>>> print(list_from_set)
[2, 4, 6, 8, 10, 12]
I have a base list [1,4,10] which needs to be converted to a list having consecutive elements of each element in the base list in an efficient way
Examples:
If I need 2 consecutive numbers then [1,4,10] will be [1,2,4,5,10,11].
If 3 consecutive numbers then [1,4,10] will be [1,2,3,4,5,6,10,11,12].
arr=[1,4,10]
con=3
[r + i for r in arr for i in range(con)]
# [1, 2, 3, 4, 5, 6, 10, 11, 12]
Here's a one liner, assuming the list is x and the number of 'consecutives' is c:
reduce(lambda a, b: a + b, map(lambda x: range(x, x+c), x))
a = [1,4,10]
k = 3 #no of consecutive
x=[range(b,b+k) for b in a]
output = [m for d in x for m in d]
Here is one way. itertools.chain removes the need for explicit nested loops.
from itertools import chain
def consecutiver(lst, n=3):
return list(chain.from_iterable(range(i, i+n) for i in lst))
res = consecutiver([1, 4, 10], 2)
# [1, 2, 4, 5, 10, 11]
res2 = consecutiver([1, 4, 10], 3)
# [1, 2, 3, 4, 5, 6, 10, 11, 12]
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.
Assume there is a list [1,9,7,3,6]. I want to produce a new list which is sorted and smaller than one of the integers, for example the integer is 7, so the new list should be list:
[1,3,6]
You can use list-comprehension to do that:
my_list = [1,9,7,3,6]
result = sorted([x for x in my_list if x < 7])
oldList = [1,9,7,3,6]
myInt = 7
newList = sorted([x for x in oldList if x < myInt])
This is a Python "list comprehension" - it looks at each element in oldList and adds it to newList if and only if it's smaller than the integer you've chosen. Additionally, the sorted() method is native in Python.
Here's a good resource for list comprehensions for the future: http://www.pythonforbeginners.com/basics/list-comprehensions-in-python
Hope that helps!
Lists have a sort method:
old_list = [1,9,7,3,6]
new_list = [x for x in old_list if x < 7]
new_list.sort()
You can use a list comprehension:
sorted([i for i in [1,9,7,3,6] if i < 7])
You can also use a generator:
sorted(i for i in [1,9,7,3,6] if i < 7)
Note: The list comprehension version executes ~2x faster.
Try this:
num = #some number
new_list = sorted(old_list)[:sorted(old_list).index(num)]
OR Alternative
num = 7
somelist = [3,6,7,1,2,8,9,4,5,12]
somelist.sort()
somelist[:somelist.index(num)]
OUTPUT:
[0, 1, 2, 3, 4, 5, 6]
aa = filter(lambda x: x < 7, [1,9,7,3,6])
aa.sort()
print aa
OUTPUT:
[1, 3, 6]
You can use list comprehension as follow
mylist = [11, 16, 9, 6, 3, 15, 1, 18, 7, 10, 13, 5, 12, 2, 0, 4, 19, 14, 17, 8]
[x for x in sorted(mylist) if x<7]
Result:
[0, 1, 2, 3, 4, 5, 6]
Hope that helps