Comparing each adjacent values of the list - python-3.x

I'm working on lists in Python 3. What am I trying to do is;
I have 2 lists one of them have custom numbers,
other one is empty.
The aim of the code is checking if 1st list's value is bigger than previous value and if it is bigger than previous element, append it to the 2nd list.
I have to use basic pythonic syntax. I cannot use any libraries etc.
list1=[5,9,3,2,7,11]
list2 = []
for i in range(len(list1)):
if list1[i] < list1[i+1]:
list2.append(list1[i+1])
print (list2)
If I run whole block of code I got;
Traceback (most recent call last):
File "<ipython-input-209-8d49a68543e3>", line 4, in <module>
if list1[i] < list1[i+1]:
IndexError: list index out of range
but when I run just list2 I get what am I expecting which is
[9,7,11]

You can't go all the way up to len(list1) - 1 for the value of i and expect i+1 to be an index in the list. list[len(list1)] is outside the list.
If you need i+1 in the loop, the loop can only go till all possible valid values of i+1 which happens to be len(list1) - 2. To get that you need to tweak the range a bit
list1=[5,9,3,2,7,11]
list2 = []
for i in range(len(list1) - 1): # iterate until penultimate index
if list1[i] < list1[i+1]:
list2.append(list1[i+1])
print (list2)

could you use the following instead of ranges? Also uses f strings to print list2
for idx, number in enumerate(list1[:-1]):
if number > list1[idx + 1]:
list2.append(list1[idx + 1])
print(f'{list2 = }')

Related

How can I remove non-unique elements from a list entered in through the input function?

Currently working through the springboard data science career track admissions test and one of the questions I got asked was to removes all on non-duplicates from a list of numbers entered via a one line of standard input separated by a space, and return a list of the the duplicates only.
def non_unique_numbers(line):
for i in line:
if line.count(i) < 2:
line.remove(i)
return line
lin = input('go on then')
line = lin.split()
print(non_unique_numbers(line))
The output is inconsistent it seems to remove every other non-duplicate at times but never removes all the non-duplicates, please can you let me know where I am going wrong.
What happens when doing for i in line is that every iteration i gets the value from an iterator created on the variable line. So by changing line you are not changing the iterator.
So, when removing an element at index, say j, all items in index i > j are moved one index down. So now your next item will be again in index j, but the loop will still continue and go to index j+1.
A good way to see this is running your function on an all-non-duplicate values:
>>> l = [0, 1, 2, 3, 4, 5]
>>> print(non_unique_numbers(l))
[1, 3, 5]
You can see that only even-indexed values were removed according to the logic described above.
What you want to do is work on a new, separate list to stack your results. For that you could use simple list comrehension:
lin = input('go on then')
line = lin.split()
print([x for x in line if line.count(x) > 1])
It is not safe to modify a list while iterating through it. The actual problem, I think, is that remove() only removes the first instance of the value, which would make the < 2 check on the last element fail and not call the remove().
Better to use a hash table to find the counts and return those with < 2 then.

encode byte data type from a binary file in python3

I have a binary file and when I open it in python, the data would look like this:
b'\x00\x20\x00\x2A\x02\x01'
the data is presented in pairs. in the above example there are 3 pairs (\x00\x20 \x00\x2A \x02\x01). I want to change the input file and then write it into a binary file. the change is as follows:
in every pair, if the 1st item is 0, the 2nd item will be in the output file. if the 1st item is 1, the 2nd item from the previous pair will be in the output file. if the 1st item is greater than 1, then it would be more complicated. it would depend on 2 items in the same pair. for example1, if the 1st item is 2 and the 2nd item is 1, to get the number for the output, the program goes 2 items back in the output and uses that item as the output.
example2: if the 1st item is 2 and the 2nd item is 2, to get the number for the output, the program goes 2 items back in the output and uses that item plus 1 item after that as the output.
here is the expected output:
b'\x20\x2A\x20'
I tried to that using the following code in python but did not return the expected output. since I am quite new at working with binary files, would you help me to fix it? or give me some tips to get such output?
data = b'\x00\x20\x00\x2A\x02\x01'
out = bytearray()
for i in range(len(data)):
if i % 2 !=0:
if data[i] ==0:
out.append(data[i+1])
elif data[i] ==1:
out.append(data[i-1])
elif data[i] >1:
n = data[i]
for j in range(n):
out.append(n[0:j])

Why `a` is treated like 2D array also?

I am new to Python programming. In this Python code first a is treated like what we call 1D array in C. But, in the middle it is treating it as a 2D array!
n=int(input("Enter number of rows: "))
a=[]
for i in range(n):
a.append([])
a[i].append(1)
for j in range(1,i):
a[i].append(a[i-1][j-1]+a[i-1][j]) #this line
if(n!=0):
a[i].append(1)
for i in range(n):
print(" "*(n-i),end=" ",sep=" ")
for j in range(0,i+1):
print('{0:6}'.format(a[i][j]),end=" ",sep=" ")
print()
I am not getting this idea. Can anyone explain what is happening in the line I have commented #this line(line number 7)? Thanks.
Python is dynamically typed and that's the reason why this is possible. The array (in python this is called a list) a can contain multiple list and values.
a=[1,"a",["abc",10]]
# Here you get the "abc" by calling
print(a[2][0])
In your example, here you append a list:
n=int(input("Enter number of rows: "))
a=[]
for i in range(n):
a.append([]) # <---- insert a list into the list
The last line above makes the list a a 2D list.
If you come from C, you are probably familiar with linked lists being implemented as containing a void * value in each node. This is the same as assigning the value of a node to the head of another linked list.

unable to delete all element satisfying condition in a python list using enumerate

i am trying to delete zero values from the list using the below code
for id,row in enumerate(list):
if row[0]=="0":
del list(id)
this works fine for input like
[0,1,3,0,9,10,0,3,0,6]
but doesn't work as expected for inputs like
[0,0,1,3,4,0,0,4,5,6,0,0].
output: [0,1,3,4,0,4,5,6,0]
I guess its because the element right after the deleted one gets the id of the deleted element and enumerate increments the id which leaves the element after the one which is deleted unchecked.
so what can be done to check all the elements ? is there a better way ?
I made a little change to your code:
mylist = [0,0,1,3,4,0,0,4,5,6,0,0]
for id,row in reversed(list(enumerate(mylist))):
if(row==0):
del mylist[id]
If you loop your list in the way you did (from start to end) and delete an element while doing it, you'll end up jumping indexes because python does not recognize that an element has been deleted from the list.
If you have an array with 10 elements inside and you delete the first (idx 0), in the next iteration you will be at index 1, but the array has been modified, so your idx 1 is the idx 2 of your array before the deletion, and the real idx 1 will be skipped.
So you just need to loop your array in reverse mode, and you won't miss indexes.
If you print the value of mylist, you'll get [1, 3, 4, 4, 5, 6].
This problem is documented on this python page under 8.3:
https://docs.python.org/3/reference/compound_stmts.html
They suggest doing it this way by using a slice. It works for me:
a = [-2,-4,3,4]
for x in a[:]:
if x < 0: a.remove(x)
print ('contents of a now: ')
print(*a)
enumerate returns an object called enumerate object and it is iterable not actually a list. second thing row is not a list it is not subscriptable.
for i,row in enumerate(l):
if row==0:
del(l[i])
you will not get result you want this way.
try this:
t=[] #a temporary list
for i in l:
if i!=0:
t.append(i)
t will contain sublist of l with non zero elements.
put the above inside a function and return the list t .

merging some entries in a python list based on length of items

I have a list of about 20-30 items [strings].
I'm able to print them out in my program just fine - but I'd like to save some space, and merge items that are shorter...
So basically, if I have 2 consecutive items that the combined lengths are less than 30, I want to join those to items as a single entry in the list - with a / between them
I'm not coming up with a simple way of doing this.
I don't care if I do it in the same list, or make a new list of items... it's all happening inside 1 function...
You need to loop through the list and keep joining items till they satisfy your requirement (size 30). Then add them to a new list when an element grows that big.
l=[] # your new list
buff=yourList[0] if len(yourList)>0 else "" # hold strings till they reach desired length
for i in range(1,len(yourList)):
# check if concatenating will exceed the size or not
t=yourList[i]
if (len(buff) + len(t) + 1) <= 30:
buff+="/"+t
else:
l.append(buff)
buff=t
l.append(buff) # since last element is yet to be inserted
You can extend method of list as follows:
a = [1,2,3]
b = [4,5,6]
a.append('/')
a.extend(b)
You just need to check the size of two list a and b as per your requirements.
I hope I understood your problem !
This code worked for me, you can check to see if that's what you wanted, it's a bit lenghty but it works.
list1 = yourListOfElements
for elem in list1:
try: # Needs try/except otherwise last iteration would throw an indexerror
listaAUX = [] # Auxiliar list to check length and join smaller elements. You can probably eliminate this using list slicing
listaAUX.append(elem)
listaAUX.append(list1[list1.index(elem)+1])
if len(listaAUX[0]) + len(listaAUX[1]) < 30:
concatenated = '/'.join(listaAUX)
print(concatenated)
else:
print(elem)
except IndexError:
print(elem)

Resources