How do you reverse a list at a given value? - python

I'm trying to design a code that will reverse a given list at the index of a given value. The rest of the list beyond the value will be printed in correct order, but I can't seem to complete it.
This is the code I have so far.
def reverse(my_list, value):
lst = []
lst2 = []
for x in range(my_list[0], my_list[value]):
x = my_list[x]
lst2.append(x)
for i in range(len(lst2)-1, -1, -1):
x = lst2[i]
lst.append(x)
for x in range(my_list[value], len(my_list)):
x = my_list[x]
lst.append(x)
print(lst)
If the input is this.
reverse([1, 2, 3, 4, 5, 6, 7, 8, 9, 10], 5)
The output should be.
[5, 4, 3, 2, 1, 6, 7, 8, 9, 10]
But instead the output is this.
[6, 5, 4, 3, 2, 7, 8, 9, 10]
Can anyone help me to determine how to get the needed output?

It would be much easier to implement with slicing:
def reverse(my_list, value):
return my_list[:value][::-1] + my_list[value::]

Indexes in first and third cycles are wrong, you have to iterate through indexes not values. Write like here:
def reverse(my_list, value):
lst = []
lst2 = []
for x in range(0, value):
x = my_list[x]
lst2.append(x)
for i in range(len(lst2)-1, -1, -1):
x = lst2[i]
lst.append(x)
for x in range(value, len(my_list)):
x = my_list[x]
lst.append(x)
print(lst)
reverse([1, 2, 3, 4, 5, 6, 7, 8, 9, 10], 5)
output: [5, 4, 3, 2, 1, 6, 7, 8, 9, 10]

Related

Creating a list of N numbers from existing list each repeated K times

I believe this is an easy problem to solve. I have searched and found a few similar answers but not an efficient way to exactly what I want to achieve.
Assuming the following list:
x = [6, 7, 8]
I want to create a new list by repeating each number k times. Assuming k=3, the result should be:
xr = [6, 6, 6, 7, 7, 7, 8, 8, 8]
I was able to accomplish this using nest loops, which I believe is very inefficient:
xr = []
for num in x: # for each number in the list
for t in range(3): # repeat 3 times
xx2.append(num)
I also tried:
[list(itertools.repeat(x[i], 3)) for i in range(len(x))]
but I get:
[[6, 6, 6], [7, 7, 7], [8, 8, 8]]
Is there a more efficient direct method to accomplish this?
You can use list comprehension:
x = [6, 7, 8]
k = 3
out = [v for v in x for _ in range(k)]
print(out)
Prints:
[6, 6, 6, 7, 7, 7, 8, 8, 8]
def repeat_k(l,k):
lo = []
for x in l:
for i in range(k):
lo.append(x)
return lo
print (repeat_k([1,2,3],5))
Output:
[1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3]
With list comprehension:
def repeat_k(l,k):
return [ x for x in l for i in range(k) ]
print (repeat_k([1,2,3],5))
Output:
[1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3]
Another possibility:
>>> x = [6, 7, 8]
>>> k = 3
>>> l = []
>>> for item in x:
... l += k * [item]
...
>>> l
[6, 6, 6, 7, 7, 7, 8, 8, 8]
You can create a convenient function:
def repeat(it, n):
for elem in it: yield from [elem] * n
Use it like:
>>> list(repeat(x, n=3))
[6, 6, 6, 7, 7, 7, 8, 8, 8]
Thanks, everyone for the answers.
It seems there is an easier and more direct way to solve this using Numpy.
np.repeat(x, 3).tolist()
prints exactly what I needed:
[6, 6, 6, 7, 7, 7, 8, 8, 8]
import itertools
x=[4,5,6]
k=3
res = list(itertools.chain.from_iterable(itertools.repeat(i, K) for i in test_list))
print (res)
It can also be solved using python inbuilt functions of itertools library. The repeat function does the task of repetition and grouping into a list is done by the from_iterable function.

problems in my list sorting code in python

I've come up with this code to sort out duplicates in a randomly arranged list of numbers.
counter = 0
randomDup_list = [0, 3, 0, 1, 9, 8, 2, 3, 4, 2, 4, 3, 5, 6, 0, 6, 5, 2, 6, 6, 7, 8, 9, 4, 4]
dup_sorted = []
for x in randomDup_list:
if len(randomDup_list) == 0:
dup_sorted.append(x)
counter +=1
elif x != randomDup_list[counter]:
for y in dup_sorted:
if y != x:
dup_sorted.append(x)
print(dup_sorted)
When I run the code there are no errors but the numbers don't seem to be appending to my new list, and it comes out blank like this: [].
The most pythonic way to do this is with a list comprehension, like so:
dup_sorted = [el for index, el in enumerate(randomDup_list) if el not in randomDup_list[:index]]
Enumerate will create a list of tuples with the first tuple element as the index in the list, [(0,0), (1,3), (2,0), ...] are the first 3 elements in your case.
Then it basically checks if el is the first occurence of el in the list and if it is, it adds el to the dup_sorted list.
List comprehensions are maybe hard to understand, but there is plenty of information about them on the internet. Good luck with learning Python!
I did not understand what you want but you can basically sort the list like that
print(sorted(randomDup_list))
and you can create your new list like that
dup_sorted = sorted(randomDup_list)
print(dup_sorted)
Hey welcome to learning python. I have been coding for a couple of years but I still use print to test my logic.
Lets break down your code and add print to each logic test
counter = 0
randomDup_list = [0, 3, 0, 1, 9, 8, 2, 3, 4, 2, 4, 3, 5, 6, 0, 6, 5, 2, 6, 6, 7, 8, 9, 4, 4]
dup_sorted = []
for x in randomDup_list:
print("start iteration")
if len(randomDup_list) == 0:
print("1 true")
dup_sorted.append(x)
counter +=1
elif x != randomDup_list[counter]:
print("2 true")
print(dup_sorted)
for y in dup_sorted:
if y != x:
print("3 true")
dup_sorted.append(x)
print("stop iteration")
print(dup_sorted)
If you run this code you will see that the first logic test will never be true in your example. So it will go to the second logic test. This will eventually evaluate to true but there will be some iterations that will be skipped. Blank blocks of start iteration stop iteration. For the last logic test this will never be true because dup_sorted will always be empty. So for y in dup_sorted will result to nothing.
Also I think sort out is ambiguous. Is it sort? filter?
You can do set(randomDup_list) for filtering out duplicates
You can do sorted(randomDup_list) for sorting out the list
You can do sorted(list(set(randomDup_list)) for a sorted filtered list
Seeing your new comments
randomDup_list = [0, 3, 0, 1, 9, 8, 2, 3, 4, 2, 4, 3, 5, 6, 0, 6, 5, 2, 6, 6, 7, 8, 9, 4, 4]
dup_sorted = []
for x in randomDup_list:
if x in dup_sorted:
continue
else:
dup_sorted.append(x)
print(dup_sorted)
This initializes an empty list. Loops through your list. Check if it exists then appends if not. Since List maintain order, you can expect the order not to change.
To remove any duplicates from the list without changing the order
Code
dup_sorted = []
for x in randomDup_list:
if not x in dup_sorted: # check if x is in output yet
dup_sorted.append(x) # add x to output
print(dup_sorted)
# Output: [0, 3, 1, 9, 8, 2, 4, 5, 6, 7]
You can use this:
counter = 0
randomDup_list = [0, 3, 0, 1, 9, 8, 2, 3, 4, 2, 4, 3, 5, 6, 0, 6, 5, 2, 6, 6, 7, 8, 9, 4, 4]
dup_sorted = []
dup_sorted.append(randomDup_list[0])
for x in range(len(randomDup_list)):
temp = 0
for y in range(len(dup_sorted)):
if randomDup_list[x] != dup_sorted[y]:
temp = temp + 1
if temp == len(dup_sorted):
dup_sorted.append(randomDup_list[x])
print(dup_sorted)

reverse ascending sequences in a list

Trying to figure out how to reverse multiple ascending sequences in a list.
For instance: input = [1,2,2,3] to output = [2,1,3,2].
I have used mylist.reverse() but of course it reverses to [3,2,2,1]. Not sure which approach to take?
Example in detail:
So lets say [5, 7, 10, 2, 7, 8, 1, 3] is the input - the output should be [10,7,5,8,7,2,3,1]. In this example the first 3 elements 5,7,10 are in ascending order, 2,7,8 is likewise in ascending order and 1,3 also in ascending order. The function should be able to recognize this pattern and reverse each sequence and return a new list.
All you need is to find all non-descreasing subsequences and reverse them:
In [47]: l = [5, 7, 10, 2, 7, 8, 1, 3]
In [48]: res = []
In [49]: start_idx = 0
In [50]: for idx in range(max(len(l) - 1, 0)):
...: if l[idx] >= l[idx - 1]:
...: continue
...: step = l[start_idx:idx]
...: step.reverse()
...: res.extend(step)
...: start_idx = idx
...:
In [51]: step = l[start_idx:]
In [52]: step.reverse()
In [53]: res.extend(step)
In [54]: print(res)
[10, 7, 5, 8, 7, 2, 3, 1]
For increasing subsequences you need to change if l[idx] >= l[idx - 1] to if l[idx] > l[idx - 1]
Walk the list making a bigger and bigger window from x to y positions. When you find a place where the next number is not ascending, or reach the end, reverse-slice the window you just covered and add it to the end of an output list:
data = [5, 7, 10, 2, 7, 8, 1, 3]
output = []
x = None
for y in range(len(data)):
if y == len(data) - 1 or data[y] >= data[y+1]:
output.extend(data[y:x:-1])
x = y
print(output)
There is probably a more elegant way to do this, but one approach would be to use itertools.zip_longest along with enumerate to iterate over sequential element pairs in your list and keep track of each index where the sequence is no longer ascending or the list is exhausted in order to slice, reverse, and extend your output list with the sliced items.
from itertools import zip_longest
d = [5, 7, 10, 2, 7, 8, 1, 3]
results = []
stop = None
for i, (a, b) in enumerate(zip_longest(d, d[1:])):
if not b or b <= a:
results.extend(d[i:stop:-1])
stop = i
print(results)
# [10, 7, 5, 8, 7, 2, 3, 1]
data = [5, 7, 10, 2, 7, 8, 1, 3,2]
def func(data):
result =[]
temp =[]
data.append(data[-1])
for i in range(1,len(data)):
if data[i]>=data[i-1]:
temp.append(data[i-1])
else:
temp.append(data[i-1])
temp.reverse()
result.extend(temp)
temp=[]
if len(temp)!=0:
temp.reverse()
result.extend(temp)
temp.clear()
return result
print(func(data))
# output [10, 7, 5, 8, 7, 2, 3, 1, 2]
You could define a general handy method which returns slices of an array based on condition (predicate).
def slice_when(predicate, iterable):
i, x, size = 0, 0, len(iterable)
while i < size-1:
if predicate(iterable[i], iterable[i+1]):
yield iterable[x:i+1]
x = i + 1
i += 1
yield iterable[x:size]
Now, the slice has to be made when the next element is smaller then the previous, for example:
array = [5, 7, 10, 2, 7, 8, 1, 3]
slices = slice_when(lambda x,y: x > y, array)
print(list(slices))
#=> [[5, 7, 10], [2, 7, 8], [1, 3]]
So you can use it as simple as:
res = []
for e in slice_when(lambda x,y: x > y, array):
res.extend(e[::-1] )
res #=> [10, 7, 5, 8, 7, 2, 3, 1]

How can I find n smallest numbers without changing the order of the first list?

I intend to get the n smallest numbers in a list but keep the numbers in the same order they appear in the list. For example:
This is my list:
A = [1, 3, 4, 6, 7, 6, 8, 7, 2, 6, 8, 7, 0]
I like to get the first three lowest numbers as it has been ordered in the first list:
[1, 2, 0]
I do not want to sort the result as:
[0, 1, 2]
I have tried:
heapq.nsmallest(3,A)
but i wonder if it is possible to retain this list as:[1, 2, 0]
By the way, I'm not a Python coder so thanks for the help in advance.
You can try this:
new_a = []
A=[1, 3, 4, 6, 7, 6, 8, 7, 2, 6, 8, 7, 0]
for a in A:
if a not in new_a:
new_a.append(a)
new_a = [i for i in new_a if i in sorted(new_a)[:3]]
Output:
[1, 2, 0]
You could use heapq.nsmallest() to get the n smallest elements from the list. Then use collections.Counter to create a multiset from that list which you can use to check which elements from the original list to include in the result, e.g.
>>> from heapq import nsmallest
>>> from collections import Counter
>>> A = [1, 3, 4, 6, 7, 6, 8, 7, 2, 6, 8, 7, 0]
>>> n = 3
>>> c = Counter(nsmallest(n, A))
>>> result = []
>>> for elem in A:
... if c.get(elem, 0):
... result.append(elem)
... c[elem] -= 1
...
>>> result
[1, 2, 0]

Sort list by frequency

Is there any way in Python, wherein I can sort a list by its frequency?
For example,
[1,2,3,4,3,3,3,6,7,1,1,9,3,2]
the above list would be sorted in the order of the frequency of its values to create the following list, where the item with the greatest frequency is placed at the front:
[3,3,3,3,3,1,1,1,2,2,4,6,7,9]
I think this would be a good job for a collections.Counter:
counts = collections.Counter(lst)
new_list = sorted(lst, key=lambda x: -counts[x])
Alternatively, you could write the second line without a lambda:
counts = collections.Counter(lst)
new_list = sorted(lst, key=counts.get, reverse=True)
If you have multiple elements with the same frequency and you care that those remain grouped, we can do that by changing our sort key to include not only the counts, but also the value:
counts = collections.Counter(lst)
new_list = sorted(lst, key=lambda x: (counts[x], x), reverse=True)
l = [1,2,3,4,3,3,3,6,7,1,1,9,3,2]
print sorted(l,key=l.count,reverse=True)
[3, 3, 3, 3, 3, 1, 1, 1, 2, 2, 4, 6, 7, 9]
You can use a Counter to get the count of each item, use its most_common method to get it in sorted order, then use a list comprehension to expand again
>>> lst = [1,2,3,4,3,3,3,6,7,1,1,9,3,2]
>>>
>>> from collections import Counter
>>> [n for n,count in Counter(lst).most_common() for i in range(count)]
[3, 3, 3, 3, 3, 1, 1, 1, 2, 2, 4, 6, 7, 9]
In case you want to use a double comparator.
For example: Sort the list by frequency in descending order and in case of a clash the smaller one comes first.
import collections
def frequency_sort(a):
f = collections.Counter(a)
a.sort(key = lambda x:(-f[x], x))
return a
Was practising this one for fun. This solution use less time complexity.
from collections import defaultdict
lis = [1,2,3,4,3,3,3,6,7,1,1,9,3,2]
dic = defaultdict(int)
for num in lis:
dic[num] += 1
s_list = sorted(dic, key=dic.__getitem__, reverse=True)
new_list = []
for num in s_list:
for rep in range(dic[num]):
new_list.append(num)
print(new_list)
def orderByFrequency(list):
listUniqueValues = np.unique(list)
listQty = []
listOrderedByFrequency = []
for i in range(len(listUniqueValues)):
listQty.append(list.count(listUniqueValues[i]))
for i in range(len(listQty)):
index_bigger = np.argmax(listQty)
for j in range(listQty[index_bigger]):
listOrderedByFrequency.append(listUniqueValues[index_bigger])
listQty[index_bigger] = -1
return listOrderedByFrequency
#tests:
print(orderByFrequency([1,2,3,4,3,3,3,6,7,1,1,9,3,2]))
print(orderByFrequency([1,2,2]))
print(orderByFrequency([1,2,1,2]))
print(orderByFrequency([2,1,2,1]))
print(orderByFrequency([3,3,3,4,4,4,4,1,5,5,5,5,5,2,2]))
print(orderByFrequency([3,3,3,6,6,6,4,4,4,4,1,6,6,5,5,5,5,5,2,2]))
print(orderByFrequency([10,20,30,30,30,40,40,50,50,50]))
results:
[3, 3, 3, 3, 3, 1, 1, 1, 2, 2, 4, 6, 7, 9]
[2, 2, 1]
[1, 1, 2, 2]
[1, 1, 2, 2]
[5, 5, 5, 5, 5, 4, 4, 4, 4, 3, 3, 3, 2, 2, 1]
[5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 4, 4, 4, 4, 3, 3, 3, 2, 2, 1]
[30, 30, 30, 50, 50, 50, 40, 40, 10, 20]
from collections import Counter
a = [2, 5, 2, 6, -1, 9999999, 5, 8, 8, 8]
count = Counter(a)
a = []
while len(count) > 0:
c = count.most_common(1)
for i in range(c[0][1]):
a.append(c[0][0])
del count[c[0][0]]
print(a)
You can use below methods. It is written in simple python.
def frequencyIdentification(numArray):
frequency = dict({});
for i in numArray:
if i in frequency.keys():
frequency[i]=frequency[i]+1;
else:
frequency[i]=1;
return frequency;
def sortArrayBasedOnFrequency(numArray):
sortedNumArray = []
frequency = frequencyIdentification(numArray);
frequencyOrder = sorted(frequency, key=frequency.get);
loop = 0;
while len(frequencyOrder) > 0:
num = frequencyOrder.pop()
count = frequency[num];
loop = loop+1;
while count>0:
loop = loop+1;
sortedNumArray.append(num);
count=count-1;
print("loop count");
print(loop);
return sortedNumArray;
a=[1, 2, 3, 4, 3, 3, 3, 6, 7, 1, 1, 9, 3, 2]
print(a);
print("sorted array based on frequency of the number");
print(sortArrayBasedOnFrequency(a));

Categories