Why does only 3 values are pop from this code? [duplicate] - python

This question already has answers here:
How to remove items from a list while iterating?
(25 answers)
Closed 1 year ago.
numbers = [2,4, 6,8, 11, 23]
popped_numbers = []
for number in numbers:
i = numbers.pop(0)
print(i)
popped_numbers.append(i)
print(numbers)
results
2
4
6
[8, 11, 23]

It is because when you are poping from numbers, then the size of it is actually changing. At the same time the iterator starts from 0 index in the array and increasing. So after picking the first 3 numbers, size of numbers is equal to 3 and iterator is also 3 and the for loop breaks. You can implement it like this:
numbers = [2,4, 6,8, 11, 23]
popped_numbers = []
while len(numbers) > 0:
i = numbers.pop(0)
print(i)
popped_numbers.append(i)
print(numbers)
print(popped_numbers)

Because the pointer, when you pop an element from the numbers list in the loop, the pointer after the third iteration is in third element, at this point the last element in the list.
Like:
Iteration | element | list
__________|_________|_______
1 | 2 | [4,6,8,11,23]
2 | 4 | [6,8,11,23]
3 | 6 | [8,11,23]

Related

is index same for same elements? [duplicate]

This question already has answers here:
Index of duplicates items in a python list
(21 answers)
Closed 1 year ago.
nums = [11, 2,4, 2, 5]
for i in nums:
print(nums.index(i),i )
I run the above code and it uses same index for similar elements(here 2 at index 1 and 3).
I wasn't aware of this python list behavior, does it mean the use of lists can be restrictive for similar elements in same list?
The index() method returns the position at the first occurrence of the specified value.
So it returns first index of number 2.
nums = [11, 2,4, 2, 5]
You can enumerate() to get all indexes.
nums = [11, 2,4, 2, 5]
for i,n in enumerate(nums):
print(i, n)
0 11
1 2
2 4
3 2
4 5

How does count work when passing an empty string? [duplicate]

This question already has answers here:
Why are str.count('') and len(str) giving different output?
(3 answers)
Closed 2 years ago.
I have a question, if I have
h = "hello world"
print (h.count(''))
That prints 12.
But if i do
print (h[11])
I get an IndexError: string index out of range
I don't understand the reason.
What does the count function count when passing an empty string?
The reason it prints 12 is that there are empty strings in between every letter, and at both sides. Here is a diagram:
All empty strings!
^h^e^l^l^o^ ^w^o^r^l^d^
it looks weird, but every ^ is an empty sn empty string, and if you count them, there are 12.
The reason you are getting the error is that a string is just an array of characters, so it is zero-indexed, meaning that the first element is index 0, the second at index 1, and so on. Here is a diagram:
-------------------------------------
a | b | c | d | e | f | g | h | i | j
-------------------------------------
0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9
-------------------------------------
As you can see, the tenth element (j), is at index 9, so trying to get index 10 would result in an error.
The String Hello World Can only be indexed up to 10. Remember that indexes start at zero
H the first character is 0
and d at the end is 10
when you do count(''), it includes a blank space after and before the String, so it adds two extra increments.
So you can do len(h)-1 or (h.count('')-2) to show the last element of the strings index.
Note len() shows how many elements are in a list not the index of the last one. The last element of a string or list is len()-1

How can I combine binary a set of data

I have a set of values vertically
2,4
4,7
5,8
9
I want to have binary combination of each two values in vertical for example 2 and 4, 2 and 5 etc . the same for the second
2 4
2 5
4 5
4 7
4 8
.
.
.
Ok it seems very complicated so I try to make it easier
I convert my data into horizon
I have
2,4,5
4,7,8,9
I want to have the binary combination of the first row
2 4
2 5
4 5
and the the binary combination of the second row
4 7
4 8
4 9
7 8
7 9
8 9
If you have values stores in two collectables, use list comprehension
from itertools import izip_longest
a = [(1,'a'),(2,'b'),(3,None)]
b,c = izip_longest(*a)
d = [(i, j) for i in b if i for j in c if j]
I think I understand. Try this code:
test.py
#!/bin/python
# put items side by side
# take first item and put the next item besides it
# if there are any more items after the next, put that item besides the first item
# if there are no more items after the next, switch to the next item in the list
# repeat
def two_items_side_by_side(mylist):
list_len = len(mylist)
for i in range(list_len):
for j in range(i+1, list_len):
print '{} {}'.format(mylist[i], mylist[j])
# -------------------------------------------------------------------
# these are two lists
list1 = [2, 4, 5]
list2 = [4, 7, 8, 9]
two_items_side_by_side(list1)
two_items_side_by_side(list2)
When you run this, your results will look like so:
Result
python test.py
2 4
2 5
4 5
4 7
4 8
4 9
7 8
7 9
8 9
If your test case is a string with each line containing comma separated text like this, you can use test2.py as an example
2,4
4,7
5,8
,9
test2.py
#!/bin/python
# put items side by side
# take first item and put the next item besides it
# if there are any more items after the next, put that item besides the first item
# if there are no more items after the next, switch to the next item in the list
# repeat
def two_items_side_by_side(mylist):
list_len = len(mylist)
for i in range(list_len):
for j in range(i+1, list_len):
print '{} {}'.format(mylist[i], mylist[j])
# -------------------------------------------------------------------
# process the data and store them into a list
# then do the same work as we did in the first example
def convert_data_into_lists():
lines = data.split('\n')
for line in lines:
# ignore empty lines
if len(line.strip()) < 1:
continue
# split by comma and ignore if we don't get 2 or more values
items = line.split(',')
if len(items) < 2:
continue
# put first item in list1 and second item in list2
if len(items[0].strip()) > 0: list1.append(items[0].strip())
if len(items[1].strip()) > 0: list2.append(items[1].strip())
# -------------------------------------------------------------------
# this is my string
data = """
2,4
4,7
5,8
,9
"""
list1 = []
list2 = []
convert_data_into_lists()
two_items_side_by_side(list1)
two_items_side_by_side(list2)
Result
python test2.py
2 4
2 5
4 5
4 7
4 8
4 9
7 8
7 9
8 9
There are more elegant ways to write this code. I have written it in a manner that will help you understand the code and try it out yourself.
Requirement change
Based on the change in requirement, data is in a text file. We will take three test cases (see in results). To accommodate the requirements, I am going to use the same code I used in test2.py. Instead of creating individual lists for each column we have in our text file, I will create one list that will dynamically contain as many lists as you have columns in your text file.
Code
#!/bin/python
# put items side by side
# take first item and put the next item besides it
# if there are any more items after the next, put that item besides the first item
# if there are no more items after the next, switch to the next item in the list
# repeat
def two_items_side_by_side(mylist):
list_len = len(mylist)
for i in range(list_len):
for j in range(i+1, list_len):
print '{} {}'.format(mylist[i], mylist[j])
# -------------------------------------------------------------------
# process the data and store them into a list
# then do the same work as we did in the first example
def convert_data_into_lists():
with open(data) as f:
lines = f.readlines()
for line in lines:
# ignore empty lines
if len(line.strip()) < 1:
continue
# split by comma and ignore if we don't get 2 or more values
items = line.split(',')
counter = 0
for item in items:
if len(mylist) < counter + 1:
mylist.append([])
if len(item.strip()) > 0:
mylist[counter].append(item.strip())
counter += 1
# -------------------------------------------------------------------
# this is my string
data = 'test.txt'
mylist = []
convert_data_into_lists()
for individual_list in mylist:
two_items_side_by_side(individual_list)
Result
Case 1
Data:
2,4
4,7
5,8
,9
Results:
2 4
2 5
4 5
4 7
4 8
4 9
7 8
7 9
8 9
Case 2
Data:
2,4
4,7
5,8
6,9
Results:
2 4
2 5
2 6
4 5
4 6
5 6
4 7
4 8
4 9
7 8
7 9
8 9
Case 3
Data:
2,4,10
4,7,11
5,8,
,9,13
Results:
2 4
2 5
2 6
4 5
4 6
5 6
4 7
4 8
4 9
7 8
7 9
8 9
10 11
10 13
11 13
EDIT
By modifying the code above to only use a single parameter, we can read the contents of a csv file and (using some form of delimiter) provide combinations across the entire data set. Just call total_zipper() and replace 'filename.txt' with your file name.
def total_zipper():
def zipper(a):
lst = []
for i in range(1,len(a)+1):
lst+=zip(a,a[i:])
return sorted(lst)
f = open('filename.txt','r')
return [zipper(line) for line in f]
This treats all lines as iterables (Strings). For readline() to work, I believe you need a return statement at the end of each line in the txt. See the input/output page for Python for more.
Here's the shortest version I could come up with. You can use the built-in zip() function. This, when combined with list slicing, results in a pythonic way to pair the values in the required order.
def zipper(a,b):
lst = []
for i in range(1,len(b)+1):
lst+=zip(a,b[i:])
return sorted(lst)
Now simply call zipper on the various rows of data.
>>> a = [2,4,5]
>>> b = [4,7,8,9]
>>> print(zipper(a,a))
[(2, 4), (2, 5), (4, 5)]
>>> print(zipper(b,b))
[(4, 7), (4, 8), (4, 9), (7, 8), (7, 9), (8, 9)]
As a side note, I tried to use list comprehension to make the code shorter. For example, the following code does the same thing as zipper(a):
def zipper(a):
return list(zip(a,a[i:]) for i in range(1,len(a)+1))
However, with zip() returning generator objects in Python 3, the results aren't as "clean" as the output from the version above. I'd have to use next() on each generator object in the list outputted by zipper in order to get the same output, but this is a tedious process. Anyone have suggestions for making the list comprehension work?

Can't delete not last single object [duplicate]

This question already has answers here:
How to remove items from a list while iterating?
(25 answers)
Closed 6 years ago.
My code should recieve a list of numbers and then output on the screen the only numbers which repeat more then once. I don't know why but it don't work with the numbers in the middle of list. My code:
a = [int(i) for i in (input().split())]
a.sort()
for number in a:
if a.count(number)==1:
a.remove(number)
else:
a.remove(a.count(number)-a.count(number)+number)
for number in a:
print(number, end=' ')
I tried changing if on while on 4th string, but then the last number is left in the list.
It should work like:
Sample Input 1: 4 8 0 3 4 2 0 3 Sample Output 1: 0 3 4
Sample Input 2: 10 Sample Output 2:
Sample Input 3: 1 1 2 2 3 3 Sample Output 3: 1 2 3
Sample Input 4: 1 1 1 1 1 2 2 2 Sample Output 4: 1 2
You could approach this problem using set instead:
a = list(map(int, input().split()))
print(" ".join(map(str, set(i for i in a if a.count(i) > 1))))
Explanation:
Firstly, it looks like you should read up on the map function. Instead of a = [int(i) for i in (input().split())], you can just use list(map(int, input().split())), which is much more Pythonic.
Secondly, the important part of the second line is set(i for i in a if a.count(i) > 1), which just creates a new list containing only the duplicates from a (i.e. [1, 2, 3, 2, 3] becomes [2, 3, 2, 3] and then applies set to it, which converts [2, 3, 2, 3] into {2, 3} (which is a set object).
In case you're wondering what map(str, ...) is for, it's so that you can print each of the elements inside your new set (e.g. {2, 3}).
You can use built-in lib collections to count list items and filter it by a required condition.
import collections
ints = map(int, input().split())
count = collections.Counter(ints)
print filter(lambda x: count[x] > 1, count)

python printing list items incremented on lines

I am trying to take a user input and print out a list of numbers in a box format onto different lines in python.
right now i have:
horizontalsize = int (input ('please enter horizontal size '))
verticalsize = int (input ('please enter vertical size '))
numbers = horizontalsize * verticalsize
mylist = []
mylist.append(range(1,numbers))
for i in range(1,numbers,horizontalsize):
print (i)
The user will input a height and width and if the height input is 5 and the width input is 3 it should print:
1 2 3
4 5 6
7 8 9
10 11 12
13 14 15
right now im currently getting:
1
4
7
10
13
How can i get the rest of the numbers to fill in?
Any help is greatly appreciated!
This should work:
for i in range(1, numbers, horizontalsize):
lst = range(i, i+horizontalsize)
print lst # format is [1,2,3]
print ' '.join(map(str,lst)) # format is "1 2 3"
You can also declare a 2D list by list comprehension, example:
>>> horizontalsize = 3
>>> numbers = 15
>>> ll = [[x for x in range(y,y+horizontalsize)]
for y in range(1,numbers,horizontalsize)]
>>> ll
[[1, 2, 3], [4, 5, 6], [7, 8, 9], [10, 11, 12], [13, 14, 15]]
>>> for line in ll:
... print ' '.join(map(str,line))
...
1 2 3
4 5 6
7 8 9
10 11 12
13 14 15
The range() you are using will start at 1, go up to numbers, and increase by horizontalsize each time. You are pulling your values for i directly from that range, so those will be the only values you get. One simple solution is to add a second, nested loop to generate the missing values (between i and i+horizontalsize).
for i in range(1,numbers,horizontalsize):
for j in range(i, i+horizontalsize):
print (j, end=" ")
print() #for the newline after every row
Your loop steps skips all the numbers between 1 and 1+horizontalsize, and you just print that number out (without worrying about putting things on the newline). You either need to insert a nested for loop, or modify your range to go over every number, and then put the newline only after specific ones.
That second solution, which uses modulo operator:
for i in range(1,(numbers+1)):
print(i,end=" ")
if i % horizontalsize == 0:
print()
Which gives me:
1 2 3
4 5 6
7 8 9
10 11 12
13 14 15

Categories