I have the list:
list_mix = [['1','2','3'],['a','b','c'], ['d','e','f'], ['g','h','i']]
The first list must be merged with other lists in the list_mis. The result should be:
['1','2','3','a','b','c']
['1','2','3','d','e','f']
['1','2','3','g','h','i']
The following code gives me "TypeError: list indices must be integers, not list":
for item in list_mix[1:]:
print (list_mix[0] + list_mix[item])
Any solution without external libraries would be appreciated.
item is the sublist already, not an index. Just use it directly:
for item in list_mix[1:]:
print (list_mix[0] + item)
The Python for statement is a Foreach loop construct, assigning each element from list_mix[1:] to item in turn.
Demo:
>>> list_mix = [['1','2','3'],['a','b','c'], ['d','e','f'], ['g','h','i']]
>>> for item in list_mix[1:]:
... print (list_mix[0] + item)
...
['1', '2', '3', 'a', 'b', 'c']
['1', '2', '3', 'd', 'e', 'f']
['1', '2', '3', 'g', 'h', 'i']
Use a list comprehension add every sublist to sublist 0 of list_mix, use list_mix[1:] to start at the element after ['1','2','3'].
[list_mix[0] + x for x in list_mix[1:]]
[['1', '2', '3', 'a', 'b', 'c'], ['1', '2', '3', 'd', 'e', 'f'], ['1', '2', '3', 'g', 'h', 'i']]
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]
is it possible to merge the numbers in a list of chars?
I have a list with some characters:
my_list = ['a', 'f', '£', '3', '2', 'L', 'k', '3']
I'm want to concatenate the adjacent numbers as follow:
my_list = ['a', 'f', '£', '32', 'L', 'k', '3']
I have this, and it works fine, but i don't really like how it came out.
def number_concat(my_list):
new_list = []
number = ""
for ch in my_list:
if not ch.isnumeric():
if number != "":
new_list.append(number)
number =""
new_list.append(ch)
else:
number = ''.join([number,ch])
if number != "":
new_list.append(number)
return new_list
What's the best way to do this?
You can use itertools.groupby:
from itertools import groupby
my_list = ['a', 'f', '£', '3', '2', 'L', 'k', '3']
out = []
for _, g in groupby(enumerate(my_list, 2), lambda k: True if k[1].isdigit() else k[0]):
out.append(''.join(val for _, val in g))
print(out)
Prints:
['a', 'f', '£', '32', 'L', 'k', '3']
you can use a variable to track the index position in the list and then just compare two elements and if they are both digits concat them by popping the index and adding it to the previous one. we leave index pointing to the same value since we popd all other elements iwll have shifted so we need to check this index again and check the next char which will now be in that index. If the char is not a digit then move the index to the next char.
# coding: latin-1
my_list = ['a', 'f', '£', '3', '2', 'L', 'k', '3']
index = 1
while index < len(my_list):
if my_list[index].isdigit() and my_list[index - 1].isdigit():
my_list[index - 1] += my_list.pop(index)
else:
index += 1
print(my_list)
OUTPUT
['a', 'f', '£', '32', 'L', 'k', '3']
Regex:
>>> re.findall('\d+|.', ''.join(my_list))
['a', 'f', '£', '32', 'L', 'k', '3']
itertools:
>>> [x for d, g in groupby(my_list, str.isdigit) for x in ([''.join(g)] if d else g)]
['a', 'f', '£', '32', 'L', 'k', '3']
Another:
>>> [''.join(g) for _, g in groupby(my_list, lambda c: c.isdigit() or float('nan'))]
['a', 'f', '£', '32', 'L', 'k', '3']
You are just trying to reduce your numbers together.
One way to accomplish this is to loop through the list, and check if it's a number using str.isnumeric().
my_list = ['a', 'f', '£', '3', '2', 'L', 'k', '3']
new_list = ['']
for c in my_list:
if c.isnumeric() and new_list[-1].isnumeric(): # Check if current and previous character is a number
new_list[-1] += c # Mash characters together.
else:
new_list.append(c)
else:
new_list[:] = new_list[1:] # Remove '' placeholder to avoid new_list[-1] IndexError
print(new_list) # ['a', 'f', '£', '32', 'L', 'k', '3']
This has also been tested with first character is numeric.
sure! this will combine all consecutive digits:
i = 0
while i < len(my_list):
if my_list[i].isdigit():
j = 1
while i+j < len(my_list) and my_list[i+j].isdigit():
my_list[i] += my_list.pop(i+j)
j += 1
i += 1
you can also do this recursively, which is maybe more elegant (in that it will be easier to build up correctly as the task becomes more complicated) but also possibly more confusing:
def group_digits(list, accumulator=None):
if list == []:
return accumulator or []
if not accumulator:
return group_digits(list[1:], list[:1])
x = list.pop(0)
if accumulator[-1].isdigit() and x.isdigit():
accumulator[-1] += x
else:
accumulator.append(x)
return group_digits(list, accumulator)
A quick and dirty way under the assumption that the non-numeric characters are not white-space:
''.join(c if c.isdigit() else ' '+ c + ' ' for c in my_list).split()
The idea is to pad with spaces the characters that you don't want merged, smush the resulting characters together so that the non-padded ones become adjacent, and then split the result on white-space, the net result leaving the padded characters unchanged and the non-padded characters joined.
I have written a beginner-friendly solution using an index and two lists:
my_list = ['a', 'f', '£', '3', '2', 'L', 'k', '3']
result = []
index = 0
for item in my_list:
if item.isdigit():
# If current item is a number
if my_list[index-1].isdigit() and len(result) > 1:
# If previous item is a number too and it is not the 1st item
# of the list, sum the two and put them in the previous slot in result
result[index-1] = my_list[index-1] + my_list[index]
else:
result.append(item)
else:
result.append(item)
index += 1
print(my_list)
print(result)
Output
['a', 'f', '£', '3', '2', 'L', 'k', '3']
['a', 'f', '£', '32', 'L', 'k', '3']
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]