I'm new to coding so I apologize if the question I'm asking is quite simple.
I'm coding a game where I have to make one large piece (represented as 1's) on a board reach to the end. There are several other smaller pieces that can be moved (2 to denote horizontal 1x2 pieces, 3 to denote vertical 1x2 pieces, and 4 to denote the single pieces), along with two empty spaces (represented as 0's).
So this is how the board initially looks like coming from a txt file:
3113
3113
3223
3443
4004
2's can be moved horizontally, 3's can be moved vertically, and the single piece (4) can be moved either horizontally or vertically.
The code below simply takes the input board and converts its rows into lists:
def initialize():
row1=[]
row1[:0] = Lines[0]
del(row1[-1])
print(row1)
row2=[]
row2[:0] = Lines[1]
del(row2[-1])
print(row2)
row3=[]
row3[:0] = Lines[2]
del(row3[-1])
print(row3)
row4=[]
row4[:0] = Lines[3]
del(row4[-1])
print(row4)
row5=[]
row5[:0] = Lines[4]
print(row5)
The output of the code looks like this:
['3', '1', '1', '3']
['3', '1', '1', '3']
['3', '2', '2', '3']
['3', '4', '4', '3']
['4', '0', '0', '4']
The issue I'm having is saving this current formation and creating a list of the next possible formations
Would appreciate any help, thank you.
I can provide more clarification if needed.
The biggest problem you have is the fact you are differentiating each row of the board as a separate variable. What you need to do is define the entire board as a list of lists referenced to by a single variable. There are a couple of ways to do this:
Using your approach of a function to initialize the board.
def initialize(lines):
brd = []
for l in lines:
row = [int(x) for x in l]
brd.append(row)
return brd
The above function call returns a list of lists describing your board, so you would use it like:
lines = ['3113', '3113', '3223', '3443', '4004']
board = initialize(lines)
for l in boards:
print(l)
produces:
[3, 1, 1, 3]
[3, 1, 1, 3]
[3, 2, 2, 3]
[3, 4, 4, 3]
[4, 0, 0, 4]
If you want to output the data in a form that resembles the initial data input you can use
for l in board:
print(''.join(str(x) for x in l))
Which produces:
3113
3113
3223
3443
4004
At this point you can add functions to move pieces and return the updated board.
A better approach would be to encapsulate the board in a class definition and utilize the power of builtin functions to aide in producing your board. In this approach you would define a Board class as follows:
class Board:
def __init__(self, lines):
self.brd = []
for l in lines:
row = [int(x) for x in l]
self.brd.append(row)
def __repr__(self):
s = ""
for rw in self.brd:
s += f"{rw}\n"
return s
You would then define your board using:
board = Board(lines)
and you can display the board using
print(board)
which produces the previous, neat board display without need to cycle through the row and you can add methods within your class description for moving pieces on your board.
This question already has answers here:
modify list elements on a condition
(3 answers)
Closed last year.
So, I want the odd numbers of the list to be multiplied by two and form a new list with the same index value but no other changes in the initial list,
for example i is the initial list and o is the output i want
i=['0','7','2','3','4']
o=['0','14','2,'6','4']
here's the code I tried:
list=["1","3","7"]
for num in list:
if num%2!=0:
num*2
print(list)
here's the error I get:
PS C:\Users\suhas\Desktop\sujan> & C:/Users/suhas/AppData/Local/Programs/Python/Python39/python.exe c:/Users/suhas/Desktop/sujan/user_testing.py
Traceback (most recent call last):
File "c:\Users\suhas\Desktop\sujan\user_testing.py", line 5, in <module>
if num%2!=0:
TypeError: not all arguments converted during string formatting
ls = ['1', '2', '3']
for i, el in enumerate(ls):
if int(el) % 2:
ls[i] = str(int(el)*2)
print(ls)
# prints ['2', '2', '6']
If you intend to not mutate the input list and create a new list for the results:
ls = ['1', '2', '3']
res = []
for el in ls:
if int(el) % 2:
res.append(str(int(el)*2))
else:
res.append(el)
print(res)
# prints ['2', '2', '6']
If the input list were only integers you wouldn't need to convert the elements to integers and back to strings, of course:
ls = [1, 2, 3]
for i, el in enumerate(ls):
if el % 2:
ls[i] = el*2
print(ls)
# prints [2, 2, 6]
Please avoid naming your lists list. This shadows the list type of python and can create a lot of confusion and subtle bugs later on.
Your error comes from the comparison if num%2!=0: where num is a str-type and 0 is an integer. To check this you can use the type function, returning what type your variable num is;
list=["1","3","7"]
for num in list:
print(type(num))
if num%2!=0:
num*2
print(list)
instead of looping through the list and saving each element as a variable, you want to iterate through a range with the length of your list. By doing so you can use the number in the range to access the index of each element of the list instead and updating the lists element if your criteria is met;
list = ['0','7','2','3','4']
# wanted output ['0','14','2','6','4']
for i in range(len(list)):
num = int(list[i])
if num%2 != 0:
list[i] = num*2
print(list)
Read some about loops and lists to get the syntax right for next try :)
w3school Python - Loop Lists
The below approach uses a list comprehension to achieve the desired list. Here, if we consider in_list as input list then no. inside list is stored as a string so while iterating over the list to check whether no. is odd or even first no. needs to be converted to int and then it is checked with % operator if it is even then it's multiplied with 2 and then result is converted back to string as the output requirement is a list of numbers stored as a string
in_list=['0','7','2','3','4']
output = [i if (int(i)%2)==0 else str(int(i)*2) for i in in_list ]
print(output)
Example is a little misleading here. If we consider odd indices then
o=[int(i[x])*2 if x%2==1 else int(i[x]) for x in range(len(i))]
If we consider numbers themselves
o= [str(int(x)*2) if int(x)%2!=0 else x for x in i]
I have a text dump of letters and numbers, and I want to filter out only valid credit card numbers (for class, I swear). I used
for item in content:
nums.append(re.sub('[^0-9]', ' ', item))
to take out everything that isn't a number, so I have a list of elements that are numbers with white space in the middle. If I don't turn the non-int characters into spaces, the numbers end up concatenated so the lengths are wrong. I want to split each element into a new element at the whitespace.
Here's a screenshot of part of the Sample output, since I can't copy it without python turning every group of multiple spaces into a single space: https://gyazo.com/4db8b8b78be428c6b9ad7e2c552454af
I want to make a new element every time there is one or more spaces. I tried:
for item in nums:
for char in item:
char.split()
and
for item in nums:
item.split()
but that ended up not changing anything.
split doesn't mutate the string but returns a list of strings instead. If you call it without storing the result as in your example it won't do anything good. Just store the result of split to new list:
>>> nums = ['1231 34 42 432', '12 345345 7686', '234234 45646 435']
>>> result = []
>>> for item in nums:
... result.extend(item.split())
...
>>> result
['1231', '34', '42', '432', '12', '345345', '7686', '234234', '45646', '435']
Alternatively you could use list comprehension to do the above on one line:
>>> [x for item in nums for x in item.split()]
['1231', '34', '42', '432', '12', '345345', '7686', '234234', '45646', '435']
For this problem I am dealing with a big list,that it was imported from a CSV file, but let's say
I have a list like this:
[['name','score1','score2''score3''score4']
['Mike','5','1','6','2']
['Mike','1','1','1','1']
['Mike','3','0','3','0']
['jose','0','1','2','3']
['jose','2','3','4','5']
['lisa','4','4','4','4']]
and I want to have another list with this form(the sum of all score for each student):
[['Mike','9','2','10','3']
['jose','2','4','6','8']
['lisa','4','4','4','4']]
any ideas how this can be done?
I've been trying many ways, and I could not make it.
I was stuck when there where more than 2 same names, my solution only kept the last 2 lines to add.
I am new in python and programming in general.
If you are just learning Python I always recommend try to implement things without relying on external libraries. A good starting step is to start by trying to break the problem up into smaller components:
Remove the first entry (the column titles) from the input list. You don't need it for your result.
For each remaining entry:
Convert every entry except the first to an integer (so you can add them).
Determine if you have already encountered an entry with the same name (first column value). If not: add the entry to the output list. Otherwise: merge the entry with the one already in the output list (by adding values in the columns).
One possible implementation follows (untested):
input_list = [['name','score1','score2''score3''score4'],
['Mike','5','1','6','2'],
['Mike','1','1','1','1'],
['Mike','3','0','3','0'],
['jose','0','1','2','3'],
['jose','2','3','4','5'],
['lisa','4','4','4','4']]
print input_list
# Remove the first element
input_list = input_list[1:]
# Initialize an empty output list
output_list = []
# Iterate through each entry in the input
for val in input_list:
# Determine if key is already in output list
for ent in output_list:
if ent[0] == val[0]:
# The value is already in the output list (so merge them)
for i in range(1, len(ent)):
# We convert to int and back to str
# This could be done elsewhere (or not at all...)
ent[i] = str(int(ent[i]) + int(val[i]))
break
else:
# The value wasn't in the output list (so add it)
# This is a useful feature of the for loop, the following
# is only executed if the break command wasn't reached above
output_list.append(val)
#print input_list
print output_list
The above is not as efficient as using a dictionary or importing a library that can perform the same operation in a couple of lines, however it demonstrates a few features of the language. Be careful when working with lists though, the above modifies the input list (try un-commenting the print statement for the input list at the end).
Let us say you have
In [45]: temp
Out[45]:
[['Mike', '5', '1', '6', '2'],
['Mike', '1', '1', '1', '1'],
['Mike', '3', '0', '3', '0'],
['jose', '0', '1', '2', '3'],
['jose', '2', '3', '4', '5'],
['lisa', '4', '4', '4', '4']]
Then, you can use Pandas ...
import pandas as pd
temp = pd.DataFrame(temp)
def test(m):
try: return int(m)
except: return m
temp = temp.applymap(test)
print temp.groupby(0).agg(sum)
If you are importing it from a cvs file, you can directly read the file using pd.read_csv
You could use better solution as suggested but if you'd like to implement yourself and learn, you can follow and I will explain in comments:
# utilities for iteration. groupby makes groups from a collection
from itertools import groupby
# implementation of common, simple operations such as
# multiplication, getting an item from a list
from operator import itemgetter
def my_sum(groups):
return [
ls[0] if i == 0 else str(sum(map(int, ls))) # keep first one since it's name, sum otherwise
for i, ls in enumerate(zip(*groups)) # transpose elements and give number to each
]
# list comprehension to make a list from another list
# group lists according to first element and apply our function on grouped elements
# groupby reveals group key and elements but key isn't needed so it's set to underscore
result = [my_sum(g) for _, g in groupby(ls, key=itemgetter(0))]
To understand this code, you need to know about list comprehension, * operator, (int, enumerate, map, str, zip) built-ins and some handy modules, itertools and operator.
You edited to add header which will break our code so we need to remove it such that we need to pass ls[1:] to groupby instead of ls. Hope it helps.
As a beginner I would consider turning your data into a simpler structure like a dictionary, so that you are just summing a list of list. Assuming you get rid of the header row then you can turn this into a dictionary:
>>> data_dict = {}
>>> for row in data:
... data_dict.setdefault(row[0], []).append([int(i) for i in row[1:]])
>>> data_dict
{'Mike': [[5, 1, 6, 2], [1, 1, 1, 1], [3, 0, 3, 0]],
'jose': [[0, 1, 2, 3], [2, 3, 4, 5]],
'lisa': [[4, 4, 4, 4]]}
Now it should be relatively easy to loop over the dict and sum up the lists (you may want to look a sum and zip as a way to do that.
This is well suited for collections.Counter
from collections import Counter, defaultdict
csvdata = [['name','score1','score2','score3','score4'],
['Mike','5','1','6','2'],
['Mike','1','1','1','1'],
['Mike','3','0','3','0'],
['jose','0','1','2','3'],
['jose','2','3','4','5'],
['lisa','4','4','4','4']]
student_scores = defaultdict(Counter)
score_titles = csvdata[0][1:]
for row in csvdata[1:]:
student = row[0]
scores = dict(zip(score_titles, map(int, row[1:])))
student_scores[student] += Counter(scores)
print(student_scores["Mike"])
# >>> Counter({'score3':10, 'score1':9, 'score4':3, 'score2':2})
collections.defaultdict
I'm reading a string which is always five numbers separated by a space, I want to split this up into five individual integers so that I can process them separately.
so far I have:
reader = csv.reader([data.data], skipinitialspace=True)
for r in reader:
print r
which allows me to print the values out, how do I store them as individual integers?
You could do it like this. Assuming s is your line from reader.
>>> s='2 3 4 5 6'
>>> s.split(' ')
['2', '3', '4', '5', '6'] #just split will give strings
>>> [int(i) for i in s.split(' ')] #typecasting to ints
[2, 3, 4, 5, 6] #now you have ints
A word of caution though, I am assuming there is no other data type in the line from reader. Otherwise this code has potential to crash. You can of course put try: except: to circumvent that or use more fine-tuned parsing techniques.
UPDATE 0: Brilliant one liner from #Pavel Annosov - map(int, s.split()). map is a nifty python in-built function which lets you map a function to any iterable.
UPDATE 1: Its fairly simple to see how this will work. but to make it even more clear to #user2152165
ints_list = []
for r in reader:
ints_list = map(int, r.strip().split(' '))
ints_list has a list of your ints. do what you want with it...