Python sort runs in list - python

I'm trying to solve an example in my book:
Write a program that generates a sequence of 20 random die tosses in a list and that prints the die values, marking the runs by including them in parentheses, like this:
1 2 (5 5) 3 1 2 4 3 (2 2 2 2) 3 6 (5 5) 6 3 1
Use the following pseudocode:
Set a boolean variable inRun to false.
For each valid index i in the list
If inRun
If values[i] is different from the preceding value
Print).
inRun = false.
If not inRun
If values[i] is the same as the following value
Print (.
inRun = true.
Print values[i].
If inRun, print).
Here is my code:
import random
min = 1
max = 6
randomToss = []
for i in range(20):
randomToss.append(random.randint(min, max))
print(randomToss)
inRun = False
for i in randomToss:
if inRun:
if randomToss[i] != i - 1:
print(")")
inRun = False
if not inRun:
if randomToss[i] == i + 1:
print("(")
inRun = True
print(randomToss[i])
if inRun:
print(")")
When it runs, I get an output like so:
[2, 5, 1, 3, 1, 4, 4, 4, 6, 4, 2, 1, 4, 1, 4, 4, 5, 1, 6, 4]
1
(
4
)
5
3
5
1
1
1
(
4
)
1
1
5
1
5
1
1
(
4
)
5
(
4
)
1
When it should look something like:
[2, 5, 1, 3, 1, 4, 4, 4, 6, 4, 2, 1, 4, 1, 4, 4, 5, 1, 6, 4]
2 5 1 3 1 (4 4 4) 6 4 2 1 4 1 (4 4) 5 1 6 4
What is wrong?

You are doing for i in randomToss: and then doing randomToss[i]. This is wrong. i here refers to the actual value in the array and not the index.
you should use the range function to generate the indices for iteration.
for i in range(len(randomToss) - 1): # <- returns the indeices
if inRun:
if randomToss[i] != randomToss[i + 1]:
print(randomToss[i], end='') # <- you must print the number before ')'
print(")", end='')
inRun = False
else: # use else since you're changing isRun inside the loop
if randomToss[i] == randomToss[i + 1]:
print("(", end='')
inRun = True
print(randomToss[i], end='')

This is what is wrong with your current code. You have an array of integers called randomToss.You are looping over each integer in the array, when you do this, you set a variable called i, which stands for the index of the array.
[1 2 5 5 3, 1] // array
[1 2 3 4 5, 6] // index values
The index is the current array element in incremental order, 1,2,3.... While inside this loop you are checking the current integer, randomToss[i], in the array to the value of the the index value. You need to check the next and previous array elements. To do this you can use the index to get the element out of the array by adding or subtracting one (remember incremental) .
for i in range(len(randomToss)-1):
if inRun:
if randomToss[i] != randomToss[i-1]:
print(")")
inRun = False
if not inRun:
if randomToss[i] == randomToss[i+1]:
print("(")
inRun = True
print(randomToss[i])

The following code works.
import random
min = 1
max = 6
randomToss = []
for i in range(20):
randomToss.append(random.randint(min, max))
print(randomToss)
inRun = False
for i in range(20): # i is the index not the value
if inRun:
if i != 0 and randomToss[i] != randomToss[i - 1]: # check boundary conditions and compare the values
print(")", end="")
inRun = False
if not inRun:
if i != 19 and randomToss[i] == randomToss[i + 1]: # check boundary conditions and compare the values
print("(", end="")
inRun = True
print(randomToss[i], end="") # check indentation with the pseudocode
if inRun:
print(")", end="")

Related

Python Count values simultaneously in two columns greater than N

Need help counting the occurrence that values in two columns are greater than a value in the same row. For example, if I want to count the number of times each row is greater than 4 and I have columns X & Y such that:
X Y
2 1
5 5
6 3
5 5
The output variable will be 2 since both numbers are greater than 4 in two rows, row 2 and 4.
Thank you
In [134]: df.gt(4).all(axis="columns").sum()
Out[134]: 2
check if values are greater than 4; gives True/False's (frame)
check if we have all True's per row; gives True/False's again (series)
sum to get the count as True -> 1, False -> 0
What about a comparison like this, in case you're not looking to use any additional packages.
x = [2, 5, 6, 5]
y = [1, 5, 3, 5]
counter = 0 # initialize counter variable
min_value = 4 # initialize min_value to compare
for x, y in zip(x, y):
# print(x, y)
if x > min_value and y > min_value:
counter += 1
print("Row Count: " + str(counter))
If you are using pandas, then you can use something like this:
import pandas as pd
x = [2, 5, 6, 5]
y = [1, 5, 3, 5]
df = pd.DataFrame(list(zip(x, y)), columns=["x", "y"])
min_value = 4 # initialize min_value to compare
counter = df.gt(min_value).all(axis="columns").sum()
print("Row Count: " + str(counter))

How do I fix this program that adds up all the integers in a list except the one that equals said sum?

I am trying to solve a problem where I have to enter several integers as an input (seperated by a whitespace), and print the integer that is the sum of all the OTHER integers.
So e.g.:
1 2 3 would give: 3, because 3 = 1 + 2
1 3 5 9 would give: 9, because 5 + 3 + 1 = 9
This is the code I currently have:
x = input().split(" ")
x = [int(c) for c in x]
y = 0
for i in range(len(x)-1):
y += x[i]
del x[i]
z = sum(x)
if y == z:
print(y)
break
else:
x.insert(i,y)
As the output, it just gives nothing no matter what.
Does anyone spot a mistake? I'd be ever greatful as I'm just a beginner who's got a lot to learn :)
(I renamed your strange name x to numbers.)
numbers = input().split()
numbers = [int(i) for i in numbers]
must_be = sum(numbers) / 2
if must_be in numbers:
print(int(must_be))
The explanation:
If there is an element s such that s = (sum of other elements),
then (sum of ALL elements) = s + (sum of other elements) = s + s = 2 * s.
So s = (sum of all elements) / 2.
If the last number entered is always the sum of previous numbers in the input sequence. Your problem lies with the x.insert(i, y) statement. For example take the following input sequence:
'1 2 5 8'
after the first pass through the for loop:
i = 0
z = 15
x = [1, 2, 5, 8]
y = 1
after the second pass through the for loop:
i = 1
z = 14
x = [1, 3, 5, 8]
y = 3
after the third pass through the for loop:
i = 2
z = 12
x = [1, 3, 8, 8]
y = 8
and the for loop completes without printing a result
If it's guaranteed that one of the integers will be the sum of all other integers, can you not just sort the input list and print the last element (assuming positive integers)?
x = input().split(" ")
x = [int(c) for c in x]
print(sorted(x)[-1])
I think this is a tricky question and can be done in quick way by using a trick
i.e create a dictionary with all the keys and store the sum as value like
{1: 18, 3: 18, 5: 18, 9: 18}
now iterate over dictionary and if val - key is in the dictionary then boom that's the number
a = [1, 3, 5, 9]
d = dict(zip(a,[sum(a)]*len(a)))
print([k for k,v in d.items() if d.get(v-k, False)])

Understanding heapq sorting algorithm

I am reading the book, "Python from Novice to Expert" by Magnus Lie Hetland (Third Edition) and came across Heaps.
There he discusses the sorting order of a heap list as "the order of
the elements is important (even though it may look a bit haphazard.."
According to him the heap algorithm has 2 rules of ordering the elements:
1) Element at i is greater than element at position i//2
If one is not made then:
2) Element at position i is lower than elements at positions 2*i and 2*i+1
I ran a code checking these rules to see if they work all the time,
from heapq import *
from random import shuffle
data = list(range(10))
heap = []
shuffle(data)
for i in data:
heappush(heap, i)
print(heap)
temp = False
#From p.240
#The order of the elements isn’t as arbitrary as it seems. They aren’t in
#strictly sorted order, but there is one
#guarantee made: the element at position i is always greater than the one
#in position i // 2 (or, conversely,
#it’s smaller than the elements at positions 2 * i and 2 * i + 1). This is
#the basis for the underlying heap
#algorithm. This is called the heap property.
for i in heap:
print('___________')
if heap[i] > heap[i//2]:
print('First if: {}>{}'.format(heap[i],heap[i//2]))
temp = True
try:
if heap[i] < heap[2*i]:
print('Second if: {}<{}'.format(heap[i],heap[i*2]))
temp = True
except IndexError:
pass
try:
if heap[i] < heap[2*i+1]:
print('Third if: {}<{}'.format(heap[i],heap[i*2+1]))
temp = True
except IndexError:
pass
else:
try:
if heap[i] < heap[2*i]:
print('Second if: {}<{}'.format(heap[i],heap[i*2]))
temp = True
except IndexError:
pass
try:
if heap[i] < heap[2*i+1]:
print('Third if: {}<{}'.format(heap[i],heap[i*2+1]))
temp = True
except IndexError:
pass
if not temp:
print('No requirement was made')
temp = False
print('___________')
As expected there were inputs that achieved the goal and some not, such as:
[0, 1, 2, 3, 5, 8, 7, 9, 4, 6]
[0, 3, 1, 5, 4, 6, 2, 7, 8, 9]
My question is are there more rules for sorting when none of these rules apply?
As mentioned in the comments, the rule you had is stated in the framework of arrays with 1-based indices. Python lists are 0-based, and thus
if a child is at heap[i], in Python heap the parent is at heap[(i - 1) // 2], not at heap[i // 2]. Conversely, if a parent is at heap[j], then its children are at heap[j * 2 + 1] and heap[j * 2 + 2]
This is easy to see if you actually take the time to draw the heap:
Example 1 Example 2 Python Index 1-based Index
0 0 0 1
1 2 3 1 1 2 2 3
3 5 8 7 5 4 6 2 3 4 5 6 4 5 6 7
9 4 6 7 8 9 7 8 9 8 9 A

Assign 0 and 1 based on values greater than in one line

Say I have an array with integers 1 through 10 and have to replace all integers less than 6 with 0 and all integers equal to or greater than 6 with 1. Currently, I am doing this:
arry[arry < 6] = 0
arry[arry >= 6] = 1
I was wondering what would be a way to combine these two statements into one line of code, or any other solution for that matter.
I assume that arry is a numpy array (the smart indexing that you are using seems to indicate this). In that case you can simply do:
arry = (arry >= 6).astype(int)
where astype(int) will convert the array of booleans arry >= 6 to an array of integers.
You can use a simple list comprehension:
array = [0 if num < 6 else 1 for num in arry]
Which is equivalent to the following loops:
temp = []
for num in arry:
if num < 6:
temp.append(0)
else:
temp.append(1)
arry = temp
[1 if e >= 6 else 0 for e in arry]
for numpy array, (arry >= 6) gives an array of True/False which you can multiply by 1
(arry >= 6) * 1
or add 0
(arry >= 6) + 0
or cast to int
(a >= 6).astype(int)
[int(e >= 6) for e in arry]
This works because True is defined to be the same value as 1 and False is defined to be the same value as 0.
list(map(lambda i: 0 if i<6 else 1, a))
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10].map(function (n) {return n >= 6 ? 1 : 0})

Constructing Lists

I'm new to Python and I came across the following query. Can anyone explain why the following:
[ n**2 for n in range(1, 6)]
gives:
[1, 4, 9, 16, 25]
It is called a list comprehension. What is happening is similar to the following:
results = []
for n in range(1,6):
results.append(n**2)
It therefore iterates through a list containing the values [0, 1, 2, 3, 4, 5] and squares each value. The result of the squaring is then added to the results list, and you get back the result you see (which is equivalent to 0**2, 1**2, 2**2, etc., where the **2 means 'raised to the second power').
This structure (populating a list with values based on some other criteria) is a common one in Python, so the list comprehension provides a shorthand syntax for allowing you to do so.
Breaking it down into manageable chunks in the interpreter:
>>> range(1, 6)
[1, 2, 3, 4, 5]
>>> 2 ** 2 # `x ** 2` means `x * x`
4
>>> 3 ** 2
9
>>> for n in range(1, 6):
...   print n
1
2
3
4
5
>>> for n in range(1, 6):
... print n ** 2
1
4
9
16
25
>>> [n ** 2 for n in range(1, 6)]
[1, 4, 9, 16, 25]
So that's a list comprehension.
If you break it down into 3 parts; separated by the words: 'for' and 'in' ..
eg.
[ 1 for 2 in 3 ]
Probably reading it backwards is easiest:
3 - This is the list of input into the whole operation
2 - This is the single item from the big list
1 - This is the operation to do on that item
part 1 and 2 are run multiple times, once for each item in the list that part 3 gives us. The output of part 1 being run over and over, is the output of the whole operation.
So in your example:
3 - Generates a list: [1, 2, 3, 4, 5] -- Range runs from the first param to one before the second param
2 - 'n' represents a single number in that list
1 - Generates a new list of n**2 (n to the power of 2)
So an equivalent code would be:
result = []
for n in range(1, 6):
result.append(n**2)
Finally breaking it all out:
input = [1, 2, 3, 4, 5]
output = []
v = input[0] # value is 1
o = v**2 # 1 to the power of two is 1
output.append(o)
v = input[1] # value is 2
o = v**2 # 2 to the power of two = (2*2) = 4
output.append(o)
v = input[2] # value is 3
o = v**2 # 3 to the power of two is = (3*3) = 9
output.append(o)
v = input[3] # value is 4
o = v**2 # 4 to the power of two is = (4*4) = 16
output.append(o)
v = input[4] # value is 5
o = v**2 # 5 to the power of two is = (5*5) = 25
output.append(o)

Categories