Related
I have this list:
new_list = ['a', '1', '--', '2', 'c', '3', 'd', '4', 'e' '5', 'f', '6', 'g', '7', 'h', '8', 'i']
It contains both numbers and words, however, the numbers are seen as strings and not integers.
I want to convert the numbers from strings to integers.
I tried with this myself:
for number in new_list:
if number.isalpha():
continue
else:
int(number)
It looks through the list and if it's something with letters it continues, however, it doesn't work when it seems "special characters" such as the two lines on the third element. I get an error message there.
I also tried this:
for number, element in enumerate(lista_lista):
if number.isalpha() == False:
int(number)
This only looks at every other element, which is a number, and uses isalpha(), and if that's False (which it should be), then I convert, but this doesn't work either.
Use number.isdigit() to recognize the numeric elements. Just because it's not alphabetic, it doesn't mean it's a number.
list_with_numers = [int(x) if x.isdigit() else x for x in new_list]
You can try this:
new_list = ['a', '1', '--', '2', 'c', '3', 'd', '4', 'e' '5', 'f', '6', 'g', '7', 'h', '8', 'i']
def to_int(x):
try:
return int(x)
except:
return x
[to_int(x) for x in new_list]
# Out[4]: ['a', 1, '--', 2, 'c', 3, 'd', 4, 'e5', 'f', 6, 'g', 7, 'h', 8, 'i']
This solution should be more performant than approaches like: int(x) if x.isdigit(), because you do not have to have call 2 different operations, like check if value is a digit and then apply the int conversion.
he below is a simple code without any error that you can use to fulfill your requirement, which is also easy to understand. Please have a check,
new_list = ['a','1','-','2','c','3','d','4','e','5','f','6','g','7','h','8','i']
for ind in range(len(new_list)):
if new_list[ind].isdigit():
new_list[ind]=int(new_list[ind])
else:
continue
print(new_list)
You can use str.isdigit and use list comprehension to modify like:
new_list = ['a', '1', '--', '2', 'c', '3', 'd', '4', 'e' '5', 'f', '6', 'g', '7', 'h', '8', 'i']
modified_list = [int(el) if el.isdigit() else el for el in new_list]
But it won't work for floats or negative integers in string form e.g. '-9', '11.5', if you need that you could do:
def convert_to_number(s):
try:
return int(s)
except:
try:
return float(s)
except:
return s
new_list = ['a', '1', '--', '2', 'c', '3', 'd', '4', 'e' '5', 'f', '6', 'g', '7', 'h', '8', 'i' ,'-9', '11.5']
print([convert_to_number(el) for el in new_list])
Output:
['a', 1, '--', 2, 'c', 3, 'd', 4, 'e5', 'f', 6, 'g', 7, 'h', 8, 'i', -9, 11.5]
Go for something like this, using list comprehension.
old_list = ['a', '1', '--', '2', 'c', '3', 'd', '4', 'e' '5', 'f', '6', 'g', '7', 'h', '8', 'i']
new_list = [int(character) if character.isdigit() else character for character in old_list]
output
['a', 1, '--', 2, 'c', 3, 'd', 4, 'e5', 'f', 6, 'g', 7, 'h', 8, 'i']
Let's analyze your code.
for number in new_list:
if number.isalpha():
continue
else:
int(number)
First of all, you iterate through new_list correctly. Now you also check if number is an alphabet that is correct. But you need to take action on that. Instead, you use continue. I suggest appending number to a list. Say it is not an alphabet, we try and turn number into an int. Sure, this works out. But your new_list will not change. Instead, you'd probably want to append number to a list. One problem I've spotted is, what if a character in the list is --. This is not an alphabet and not an integer. So by default, we will move to the else and try and perform int('--') which will return an error. So using .isdigit() is the best bet.
Use isdigit instead:
[int(x) if x.isdigit() else x for x in new_list]
I'm trying to generate an array of strings (or any other data structure that might be more useful for my task, but I can't think of anything else) in Python.
The program I'm working on has several sets of radio buttons. For example a set of "Block"/"Alternate" and "Single"/"Duplicate".
Examples on how the array of strings should look when they are activated:
Block, Single:
list = ['A', 'B', 'C', '1', '2', '3']
Alternating, Single:
list = ['A', '1', 'B', '2', 'C', '3']
Alternating, Duplicate:
list = ['A', 'A', '1', '1', 'B', 'B', '2', '2', 'C', 'C', '3', '3']
Those are only several examples, the program has way more, but the concept is the same.
I need to read this array of strings and use it as a schema of sorts to further select some data from my Pandas Dataframe.
How would I go about generating this array without writing an if clause for every single possible combination?
I tried to solve this using Jupyter Notebook and some widgets for the user interaction. I don' know how you get this informations but to replicate the same behaviour I am using this.
In [1]:
import ipywidgets as widgets # Widgets for user interactions
## Change the list as you want
my_list = ['A', 'B', 'C', '1', '2', '3']
single_duplicate = widgets.ToggleButtons(
description='Do you want to Duplicate the list ?',
options=['Single', 'Duplicate'],
value='Single',
style={'description_width': 'initial'}
)
single_duplicate
Out [1]:
In [2]:
block_alter = widgets.ToggleButtons(
description='Do you want to Alternate the list?',
options=['Block', 'Alternate'],
value='Block',
style={'description_width': 'initial'}
)
block_alter
Out [2]:
Then define the function to manipulate the list with the user input
In [3]:
def get_array(single_duplicate, block_alter, my_list):
temporary_list = []
## Answer to Single or Duplicate
if single_duplicate == 'Duplicate':
for elem in my_list:
temporary_list.append(elem)
temporary_list.append(elem)
else:
temporary_list = my_list
## Answer to Block or Aternate ?
new_list = []
if block_alter == 'Alternate':
half = int(len(temporary_list)/2)
for i in range(half):
new_list.append(temporary_list[i])
new_list.append(temporary_list[i + half])
else:
new_list = temporary_list
return new_list
Use get_array(single_duplicate.value, block_alter.value, my_list) to see the output with the user's choses
Here some exemples
In [3]:
print(get_array('Single', 'Block', my_list))
print(get_array('Duplicate', 'Block', my_list))
print(get_array('Single', 'Alternate', my_list))
print(get_array('Duplicate', 'Alternate', my_list))
Out [3]:
['A', 'B', 'C', '1', '2', '3']
['A', 'A', 'B', 'B', 'C', 'C', '1', '1', '2', '2', '3', '3']
['A', '1', 'B', '2', 'C', '3']
['A', '1', 'A', '1', 'B', '2', 'B', '2', 'C', '3', 'C', '3']
>>> import itertools
>>> a = ['1', '2', '3', '4', '5']
>>> b = ['a', 'b', 'c', 'd', 'e', 'f']
>>> list(itertools.chain.from_iterable(zip(a,b)))
['1', 'a', '2', 'b', '3', 'c', '4', 'd', '5', 'e']
As you can see, I have two asymmetrical list and I want to mix them like above. The problem is it ignore the last item.
Expected:
['1', 'a', '2', 'b', '3', 'c', '4', 'd', '5', 'e', 'f']
Actual:
['1', 'a', '2', 'b', '3', 'c', '4', 'd', '5', 'e']
Since you're using itertools in the first place, I assume you want this to work on any iterables, not just lists, and ideally without eagerly listifying them first. Otherwise, just do this:
list(itertools.chain.from_iterable(zip(a,b))) + a[len(b):] + b[len(a):]
The zip_longest function almost does what you want out of the box, but it inserts a fillvalue (default None) for each slot once the shorter iterable runs out. If your values are all truthy, you can just filter those out with if i as in Ajax1234's answer, or filter with None as the predicate, but if your values can be anything in Python, even None, the only way to do it gets pretty clunky:
_sentinel = object()
[elem for elem in itertools.chain.from_iterable(itertools.zip_longest(a, b, fillvalue=_sentinel))
if elem is not _sentinel]
But you can look at how zip_longest works and do the same thing yourself, only generating "incomplete" tuples instead of "filled-in" tuples, and then call it like this:
list(itertools.chain.from_iterable(zip_longest_nofill(a, b)))
Although making a variant of the zip_longest code from the docs that's easy enough to explain in an SO answer is a bit challenging, so maybe it's better to use an explicit loop:
def zip_longest_nofill(*args):
empty = object()
its = [iter(arg) for arg in args]
while True:
vals = (next(it, empty) for it in its)
tup = tuple(val for val in vals if val is not empty)
if not tup:
return
yield tup
I think this version is a lot easier to understand (although it was actually a bit harder to write…)
Of course if the only thing you're ever going to use zip_longest_nofill for is to implement your flattened_zip_nofill, it's even easier to just inline it into the flattening part, at which point you end up with basically the two-liner in the last section.
Instead of chain, use zip_longest:
import itertools
a = ['1', '2', '3', '4', '5']
b = ['a', 'b', 'c', 'd', 'e', 'f']
new_results = [i for b in itertools.zip_longest(a, b) for i in b if i is not None]
Output:
['1', 'a', '2', 'b', '3', 'c', '4', 'd', '5', 'e', 'f']
Just manually append the remaining:
def mix(a, b):
c = list(itertools.chain.from_iterable(zip(a,b)))
c += a[len(b)] + b[len(a):]
return c
One liner:
mix = lambda a, b: list(itertools.chain.from_iterable(zip(a,b))) + a[len(b)] + b[len(a):]
This should work but it's not very elegant
lst = []
for i in range(temp = max(len(a), len(b))):
if i < len(a): lst.append(a[i])
if i < len(b): lst.append(b[i])
lst
You can try itertools zip_longest:
a = ['1', '2', '3', '4', '5']
b = ['a', 'b', 'c', 'd', 'e', 'f']
import itertools
output=[]
for i in itertools.zip_longest(a,b):
if i[0]==None:
output.append(i[1])
else:
output.extend([i[0],i[1]])
print(output)
output:
['1', 'a', '2', 'b', '3', 'c', '4', 'd', '5', 'e', 'f']
Consider following example
index_abcd = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i']
data = ['1', '2', '3', '4', '5', '6', '7', '8', '9']
df = pd.DataFrame(data, index=index_abcd)
index_id= df.index
I want to find the position of 'a' in the index "index_id". How do I do that. Trying
index_id.index('a')
does not work (error 'Index' object has no attribute 'index'). Thanks a lot
I suggest you to type :
index_id.get_loc("a")
Try this:
index = pd.Index(list(df))
print index.get_loc('a')
If I understand you correctly, this may be what you want:
print(df.ix['a'].index.tolist())
Output:
[0]
I'm working some code for my second ever assignment, a Go Fish game in python. For one of my function definitions, I need to take out the target_rank out of the target_player list of cards, and append it to the current players card list. I have tried using for loops, but receive errors for changing the length of the list. So far the code I have is
def Hit(player_number, target_player, target_rank, pHands):
while str(target_rank) in pHands[target_player]:
pHands[player_number].append(pHands[target_player].pop(target_rank))
print pHands[player_number]
print pHands[target_player]
pHands = [['a', '2', '3', '4', '4', '5', '6', '7', '7', 't'], ['2', 'q', '6', '9', '5', 'k', 'k', 'a', '3', '8'], ['j', '9', 't', 't', '2', 't', '7', 'j', '5', '9'], ['8', '8', 'a', 'q', 'k', '4', '6', '9', 'q', '2']]
Hit (0,1,'a',pHands)
Where pHands is a list of lists of the players card. I understand I can't use pop since target rank is a string and not the place value, but any help would be much appreciated. Thanks everyone!
I think it might be clearer not to chain the pop with the append. Moreover, pop requires an index number, not the card value itself, so it is a little awkward to use here. Instead, you could use remove:
def Hit(player_number, target_player, target_rank, pHands):
while target_rank in pHands[target_player]:
pHands[target_player].remove(target_rank)
pHands[player_number].append(target_rank)
print pHands[player_number]
print pHands[target_player]
However, pop and remove are O(n) operations. Doing that once for every card in pHands[target_player] makes the while-loop O(n**2). It would be better if we could perform the task in O(n), and that is possible with append, which is an O(1) operation. So if all we need to do is append once for each card in pHands[target_player], then the for-loop (below) is O(n):
def Hit(player_number, target_player, target_rank, pHands):
new_target_hand = []
for card in pHands[target_player]:
if target_rank == card:
pHands[player_number].append(card)
else:
new_target_hand.append(card)
pHands[target_player] = new_target_hand
print pHands[player_number]
print pHands[target_player]
EDIT: Mine works but THIS one is cleaner.
def Hit(player_number, target_player, target_rank, pHands):
try:
while True:
pHands[player_number].append(pHands[target_player].pop(pHands.index(target_rank)))
print pHands[player_number]
print pHands[target_player]
except ValueError:
pass # value no longer in hand
pHands = [['a', '2', '3', '4', '4', '5', '6', '7', '7', 't'], ['2', 'q', '6', '9', '5', 'k', 'k', 'a', '3', '8'], ['j', '9', 't', 't', '2', 't', '7', 'j', '5', '9'], ['8', '8', 'a', 'q', 'k', '4', '6', '9', 'q', '2']]
Hit (0,1,'a',pHands)