I'm trying to do a game of life. There's this weird bug I can't really fix because I don't really know where the problem is? I'm guessing it's in the loop? I don't really know. I tried to debug it using the if total > 0 print(total), and the total is only 2 when it should've been 3. I'm sorry if i'm explaining it confusing because i'm also confused.
def test():
board = [[0, 0, 0, 0, 0],
[0, 0, 1, 0, 0],
[0, 0, 1, 0, 0],
[0, 0, 1, 0, 0],
[0, 0, 0, 0, 0]]
#Tracking the neighbor, it shows that there is 3 alive neighbors in
#here.
print(board[2][1])
print(board[2-1][1+1])
print(board[2][1+1])
print(board[2+1][1+1])
return board
def update(grid, N):
newGrid = grid.copy()
for i in range(N):
if i == 0 or i == 4:
continue
for j in range(N):
if j == 0 or j == 4:
continue
total = 0
total = total + grid[i][j-1] #
total = total + grid[i][j+1] #
total = total + grid[i-1][j] #
total = total + grid[i+1][j] #
total = total + grid[i-1][j-1] #
total = total + grid[i-1][j+1] #
total = total + grid[i+1][j-1] #
total = total + grid[i+1][j+1] #
# In here it only states that there's only 2 alive neighbors
# when there should've been 3
if total > 0:
print(total)
# apply Conway's rules
if grid[i][j] == 1:
if (total < 2) or (total > 3):
newGrid[i][j] = 0
elif total == 3:
newGrid[i][j] = 1
else:
if total == 3:
newGrid[i][j] = 1
grid[:] = newGrid[:]
return(grid)
f = 0
zboard = test()
while f <= 3:
print("Generation: " + str(f))
gen = update(zboard, 5)
for i in gen:
print(i)
f += 1
You need to use deepcopy.
When you do newGrid = grid.copy(), since you have a 2D-list, the sublists in newGrid will not be independent from the sublists from grid. Your problem was that grid was updated each time you updated newGrid.
You need to replace this:
newGrid = grid.copy()
by this :
import copy
newGrid = copy.deepcopy(grid)
Here is an example to show you what was happening. cop_1 is a dependent copy whereas cop_2 is an independent one :
board = [[0, 0],
[0, 0]]
cop_1 = board.copy()
import copy
cop_2 = copy.deepcopy(board)
board[0][0] = 3 # change a value of board
print("cop_1[0][0] =", cop_1[0][0])
# cop_1[0][0] = 3
print("cop_2[0][0] =", cop_2[0][0])
# cop_2[0][0] = 0
If you run the code like you posted, you get a mistake because you didn't indent the lines after your function def test(): until return board
import random
def lottery(lucky_numbers, run):
i = 0
while i < run:
x = random.uniform(0, 1) #prints out a random number between 0 and 1
numbers = lucky_numbers
NewNumbers = numbers[-1:] + numbers[:-1] #shifts each element in the to the right
lucky_numbers = NewNumbers
print(lucky_numbers, x)
i += 1
lottery([1, 2, 0], 3)
This code prints out something like:
>>>>>>>>>>
[0, 1, 2] 0.33016179294984127
[2, 0, 1] 0.7797639530009745
[1, 2, 0] 0.6292245916315391
>>>>>>>>>>
The x values will always be different because they are random numbers between 0 and 1.
I am trying to add a function that says if x is the lowest value(min) in the loop then the programme should print the list of that iteration, for example in this case the lowest value of x in this loop is 0.33016179.. , the program should therefore print the list [0, 1, 2]
I would just save the info in a variable and print it after the loop ends:
import random
def lottery(lucky_numbers, run):
i = 0
min_x = 1
while i < run:
x = random.uniform(0, 1) #prints out a random number between 0 and 1
numbers = lucky_numbers
NewNumbers = numbers[-1:] + numbers[:-1] #shifts each element in the to the right
lucky_numbers = NewNumbers
if x < min_x:
min_x = x
min_lucky_numbers = lucky_numbers
i += 1
print(min_lucky_numbers, min_x)
lottery([1, 2, 0], 3)
You can create a "cache" that stores all the x values then call the lowest value.
cache = []
for _ in range(3):
x = random.uniform(0, 1)
cache.append(x)
print min(cache)
to do what you want, you have just to store your items in two different lists, sort them and display the firt elements of each one :
import random
luckiest_num = list()
luckiest_list = list()
def lottery(lucky_numbers, run):
i = 0
while i < run:
x = random.uniform(0, 1)
numbers = lucky_numbers
NewNumbers = numbers[-1:] + numbers[:-1]
print(NewNumbers, x)
i += 1
luckiest_num.append(x)
luckiest_list.append(NewNumbers)
lottery([1, 2, 0], 3)
luckiest_num.sort()
luckiest_list.sort()
print ("The luckiest item is : ")
print(luckiest_num[0],luckiest_list[0])
How to find the majority votes for a list that can contain -1s, 1s and 0s?
For example, given a list of:
x = [-1, -1, -1, -1, 0]
The majority is -1 , so the output should return -1
Another example, given a list of:
x = [1, 1, 1, 0, 0, -1]
The majority vote would be 1
And when we have a tie, the majority vote should return 0, e.g.:
x = [1, 1, 1, -1, -1, -1]
This should also return zero:
x = [1, 1, 0, 0, -1, -1]
The simplest case to get the majority vote seem to sum the list up and check whether it's negative, positive or 0.
>>> x = [-1, -1, -1, -1, 0]
>>> sum(x) # So majority -> 0
-4
>>> x = [-1, 1, 1, 1, 0]
>>> sum(x) # So majority -> 1
2
>>> x = [-1, -1, 1, 1, 0]
>>> sum(x) # So majority is tied, i.e. -> 0
0
After the sum, I could do this check to get the majority vote, i.e.:
>>> x = [-1, 1, 1, 1, 0]
>>> majority = -1 if sum(x) < 0 else 1 if sum(x)!=0 else 0
>>> majority
1
>>> x = [-1, -1, 1, 1, 0]
>>> majority = -1 if sum(x) < 0 else 1 if sum(x)!=0 else 0
>>> majority
0
But as noted previously, it's ugly: Python putting an if-elif-else statement on one line and not pythonic.
So the solution seems to be
>>> x = [-1, -1, 1, 1, 0]
>>> if sum(x) == 0:
... majority = 0
... else:
... majority = -1 if sum(x) < 0 else 1
...
>>> majority
0
EDITED
But there are cases that sum() won't work, #RobertB's e.g.
>>> x = [-1, -1, 0, 0, 0, 0]
>>> sum(x)
-2
But in this case the majority vote should be 0!!
I am assuming that votes for 0 count as votes. So sum is not a reasonable option.
Try a Counter:
>>> from collections import Counter
>>> x = Counter([-1,-1,-1, 1,1,1,1,0,0,0,0,0,0,0,0])
>>> x
Counter({0: 8, 1: 4, -1: 3})
>>> x.most_common(1)
[(0, 8)]
>>> x.most_common(1)[0][0]
0
So you could write code like:
from collections import Counter
def find_majority(votes):
vote_count = Counter(votes)
top_two = vote_count.most_common(2)
if len(top_two)>1 and top_two[0][1] == top_two[1][1]:
# It is a tie
return 0
return top_two[0][0]
>>> find_majority([1,1,-1,-1,0]) # It is a tie
0
>>> find_majority([1,1,1,1, -1,-1,-1,0])
1
>>> find_majority([-1,-1,0,0,0]) # Votes for zero win
0
>>> find_majority(['a','a','b',]) # Totally not asked for, but would work
'a'
You could use statistics.mode if you were using python >= 3.4 ,catching a StatisticsError for when you have no unique mode:
from statistics import mode, StatisticsError
def majority(l):
try:
return mode(l)
except StatisticsError:
return 0
The statistics implementation itself uses a Counter dict:
import collections
def _counts(data):
# Generate a table of sorted (value, frequency) pairs.
table = collections.Counter(iter(data)).most_common()
if not table:
return table
# Extract the values with the highest frequency.
maxfreq = table[0][1]
for i in range(1, len(table)):
if table[i][1] != maxfreq:
table = table[:i]
break
return table
def mode(data):
"""Return the most common data point from discrete or nominal data.
``mode`` assumes discrete data, and returns a single value. This is the
standard treatment of the mode as commonly taught in schools:
>>> mode([1, 1, 2, 3, 3, 3, 3, 4])
3
This also works with nominal (non-numeric) data:
>>> mode(["red", "blue", "blue", "red", "green", "red", "red"])
'red'
If there is not exactly one most common value, ``mode`` will raise
StatisticsError.
"""
# Generate a table of sorted (value, frequency) pairs.
table = _counts(data)
if len(table) == 1:
return table[0][0]
elif table:
raise StatisticsError(
'no unique mode; found %d equally common values' % len(table)
)
else:
raise StatisticsError('no mode for empty data')
Another way using a Counter and catching an empty list:
def majority(l):
cn = Counter(l).most_common(2)
return 0 if len(cn) > 1 and cn[0][1] == cn[1][1] else next(iter(cn),[0])[0]
You can count occurences of 0 and test if they are majority.
>>> x = [1, 1, 0, 0, 0]
>>> if sum(x) == 0 or x.count(0) >= len(x) / 2.0:
... majority = 0
... else:
... majority = -1 if (sum(x) < 0) else 1
... majority
0
This solution is based on counting occurrences and sorting:
import operator
def determineMajority(x):
'''
>>> determineMajority([-1, -1, -1, -1, 0])
-1
>>> determineMajority([1, 1, 1, 0, 0, -1])
1
>>> determineMajority([1, 1, 1, -1, -1, -1])
0
>>> determineMajority([1, 1, 1, 0, 0, 0])
0
>>> determineMajority([1, 1, 0, 0, -1, -1])
0
>>> determineMajority([-1, -1, 0, 0, 0, 0])
0
'''
# Count three times
# sort on counts
xs = sorted(
[(i, x.count(i)) for i in range(-1,2)],
key=operator.itemgetter(1),
reverse=True
)
if xs[0][1] > xs[1][1]:
return xs[0][0]
else:
# tie
return 0
if __name__ == '__main__':
import doctest
doctest.testmod()
Additionally, there is one if statements. As mentioned in the comments it is undefined what happens with
x = [1, 1, 0, 0, -1]
# These are your actual votes
votes = [-1, -1, -1, -1, 0]
# These are the options on the ballot
ballot = (-1, 0, 1)
# This is to initialize your counters
counters = {x: 0 for x in ballot}
# Count the number of votes
for vote in votes:
counters[vote] += 1
results = counters.values().sort()
if len(set(values)) < len(ballot) and values[-1] == values [-2]:
# Return 0 if there's a tie
return 0
else:
# Return your winning vote if there isn't a tie
return max(counters, key=counters.get)
A very simple approach.
a = [-1, -1, -1, -1, 0] # Example
count = {}
for i in a:
if i not in count:
count[i] = 1
else:
count[i] += 1
m_count = max(count.values())
for key in count:
if count[key] == m_count:
print key
In the above example the output will be -1,
however if there is a tie, both the keys will be printed.
I believe this works for all provided test cases. Please let me know if I did something wrong.
from collections import Counter
def fn(x):
counts = Counter(x)
num_n1 = counts.get(-1, 0)
num_p1 = counts.get(1, 0)
num_z = counts.get(0, 0)
if num_n1 > num_p1:
return -1 if num_n1 > num_z else 0
elif num_p1 > num_n1:
return 1 if num_p1 > num_z else 0
else:
return 0
from collections import Counter
result = Counter(votes).most_common(2)
result = 0 if result[0][1] == result[1][1] else result[0][0]
Error handling for empty votes lists or votes lists with a set cardinality of 1 is trivial and left as an exercise for the reader.
This works with any number of candidates. If there is a tie between two candidates it returns zero else it returns candidate with most votes.
from collections import Counter
x = [-1, -1, 0, 0, 0, 0]
counts = list((Counter(x).most_common())) ## Array in descending order by votes
if len(counts)>1 and (counts[0][1] == counts[1][1]): ## Comparing top two candidates
print 0
else:
print counts[0][0]
We compare only two candidates because if there is a tie between two candidates it should return 0 and it doesn't depend on third candidate value
An obvious approach is making a counter and updating it according to the data list x. Then you can get the list of numbers (from -1, 0, 1) that are the most frequent. If there is 1 such number, this is what you want, otherwise choose 0 (as you requested).
counter = {-1: 0, 0: 0, 1: 0}
for number in x:
counter[number] += 1
best_values = [i for i in (-1, 0, 1) if counter[i] == max(counter.values())]
if len(best_values) == 1:
majority = best_values[0]
else:
majority = 0
You don't need anything but built-in list operators and stuff, no need to import anything.
votes = [ -1,-1,0,1,0,1,-1,-1] # note that we don't care about ordering
counts = [ votes.count(-1),votes.count(0),votes.count(1)]
if (counts[0]>0 and counts.count(counts[0]) > 1) or (counts[1]>0 and counts.count(counts[1])>1):
majority=0
else:
majority=counts.index(max(counts))-1 # subtract 1 as indexes start with 0
print majority
3d line puts counts of respective votes in a new list, and counts.index() shows us which list position we find the max votes.
I would dare to say that this should be about as pythonic as it can, without getting into eye-gouging oneliners.
Upd: rewrote without text strings and updated to return 0 in case of several equal results (didnt notice this in the original post), added an IF for case if only one vote, eg votes=[-1]
from collections import Counter
def find_majority_vote(votes):
counter = Counter(votes)
most_common = counter.most_common(2)
if len(most_common)==2:
return 0 if most_common[0][1] == most_common[1][1] else most_common[0][0]
else:
return most_common[0][0]
import numpy as np
def fn(vote):
n=vote[np.where(vote<0)].size
p=vote[np.where(vote>0)].size
ret=np.sign(p-n)
z=vote.size-p-n
if z>=max(p,n):
ret=0
return ret
# some test cases
print fn(np.array([-1,-1, 1,1,1,1,0,0,0,0,0,0,0,0]))
print fn(np.array([-1, -1, -1, 1,1,1,0,0]))
print fn(np.array([0,0,0,1,1,1]))
print fn(np.array([1,1,1,1, -1,-1,-1,0]))
print fn(np.array([-1, -1, -1, -1, 1, 0]))
Hi im trying to create a game where the computer generates 5 random numbers between 1 and 6. but my issue is i have created a list which will gain '1' in its respective section depending on what number comes up. e.g. if the computer generates 31534 the list needs to show [1,0,2,1,1,0] (because there was two 3's it fills 2 in the 3 slot) it only displays the 5 random numbers and nothing else
from random import randint
def rollDice():
dice = [str(randint(1, 6)) for _ in range(5)]
print(dice)
return dice
#-----------------------------------------------------------------
def countVals(dice):
totals = [0, 0, 0, 0, 0]
for x in dice:
if x == 1:
totals = totals[1] + 1
elif x == 2:
totals = totals[2] + 1
elif x == 3:
totals = totals[3] + 1
elif x == 4:
totals = totals[4] + 1
elif x == 5:
totals = totals[5] + 1
print(totals)
return totals
#------------------------------------------------------------------
rollDice()
countVals()
I believe your error lies when you increment the count of each number,
totals = totals[1] + 1
should be,
totals[1] = totals[1] + 1
Also depending on your application you may be able to simplify your code
def countVals(dice):
totals = [0, 0, 0, 0, 0]
for x in dice:
totals[x - 1] += 1
print (totals)
return totals
I think the problem is that the result returned by your rollDice function is a list of strings. The if - else statement in countVals then falls through cause for example '5' == 5 -> False. You could modify rollDice to return a list of int's instead (don't convert your ints to strings):
def rollDice():
dice = [randint(1, 6) for _ in range(5)]
print(dice)
return dice
If you absolutely want rollDice to return a list of strings you could convert the strings to ints using the int method in your countVals method. Example: int('5') -> 5, or just compare strings and not ints. x == '5'
Also make sure that you are saving your totals back to the right index in you totals list (in rollDice). You could do this a little more succinctly as follows: totals[1] += 1, for example:
def countVals(dice):
totals = [0, 0, 0, 0, 0, 0] #alternatively could be 'totals = [0]*6' :)
for value in dice:
totals[value - 1] += 1
print(totals)
return totals
(assuming rollDice has been modified to return a list of integers)
You should be able to call the methods as follows totals = countVals(rollDice()) to get your list of totals.
You could try the following:
dice = rollDice()
countVals(dice)
Also you want to fix the indentation of the print and return statements in countVals(). Currently, they only trigger if x==5. And as Salvador Dali mentions, either remove str from rollDice() or change the comparisons in countVals() to x == '1', etc.
Edit:
Here is how you may want to write your script:
def rollDice():
dice = [randint(1, 6) for _ in range(5)]
print(dice)
return dice
def countVals(dice):
totals = [0, 0, 0, 0, 0]
for x in dice:
# x can be, 1-5. Index of totals can be 0-4.
totals[x-1] += 1
print(totals)
return totals
dice = rollDice()
countVals(dice)