Python: merge adjacent number in list - python

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']

Related

How to convert string elements in a list into integers

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]

How to compare element in list with the next element and separate if same?

I have a string, that contains random letters and numbers, but if there are two letters or numbers that are same and next to each other, then you have to separate them with "/". So the input string is "uBBjkko", and the result should be "uB/Bjk/ko".
Right now I have converted my string to list so I could compare every element to the the next:
mylist ['u', 'B', 'B', 'j', 'k', 'k', 'o']
for i in range(len(mylist)):
if mylist[i] == mylist[i + 1]:
mylist.insert(i + 1, "/")
print("".join(mylist))
but the code doesn't work if the list gets too long and if the list ends with two same letters or number such as
['u', 'B', 'B', 'j', 'k', 'k', 'o', '2', '2']
then the output will be "uB/Bjk/ko22" but it needs to be "uB/Bjk/ko2/2".
So as I said in the comment the problem is, that you insert while iterating. By iterating the other way around from end to begin you fix it. This way your iteration is not affected by the insertion:
mylist = ['u', 'B', 'B', 'j', 'k', 'k', 'o', '2', '2']
for i in range(len(mylist)-1, 0, -1): # This goes from len(mylist)-1 to 0 in -1 steps
if mylist[i] == mylist[i-1]:
mylist.insert(i, '/')
print("".join(mylist))
from itertools import zip_longest
mylist = ['u', 'B', 'B', 'j', 'k', 'k', 'o', '2', '2']
print("".join([a + ('/' if a == b else '') for a,b in zip_longest(mylist, mylist[1:], fillvalue='')]))
Though it may be a bit much, you can learn about itertools module. zip function or zip_longest function in this case and list comprehension too.

Create a list using the letters in x

Using list comprehension, create a list of all the letters used in x.
x = ‘December 11, 2018’
I tried writing each letter out but I am receiving a syntax error!
In Python a string acts as a list; it is easier and quicker to convert the list into a set (only unique values) and then back to a list:
unique_x = list(set(x))
Or if you must use list comprehension:
used = set()
all_x = "December 11, 2018"
unique_x = [x for x in all_x if x not in used and (used.add(x) or True)]
x = "December 11, 2018"
lst = [letter for letter in x]
print(lst) # test
Output:
['D', 'e', 'c', 'e', 'm', 'b', 'e', 'r', ' ', '1', '1', ',', ' ', '2', '0', '1', '8']
You can make a list comprehension like:
x = ‘December 11, 2018’
new_list = [letter for letter in x]
print(new_list)
# Output
# ['D', 'e', 'c', 'e', 'm', 'b', 'e', 'r', ' ', '1', '1', ',', ' ', '2', '0', '1', '8']
Alternatively, you could skip the list comprehension and just use new_list = list(x) to get the same result.
if you want only the letters and no spaces, you can use .replace on x like: x.replace(' ','') or add on if clause in your list comprehension:
new_list = [letter for letter in x if letter != ' ']
This should work
x = list('December 11, 2018')
print(x)
result = []
for item in x:
try:
int(item)
except ValueError:
if item == "," or item == " ":
pass
else:
result.append(item)
print(result)
"""
Output:
['D', 'e', 'c', 'e', 'm', 'b', 'e', 'r']
"""
If you are using only dates with that format, you could do this
x = "December 11, 2018".split()
print(x[0])
"""
Output:
'December'
"""

add a single spaces in list containing characters

I am new to the programming. I have a list. List contains multiple spaces. All the multiple spaces should be replaced with single space.
lis = ['h','e','l','l','','','','','o','','','','w']
output = ['h','e','l','l','','o','','w']
Could anyone tell how to do?
Just simple list comprehension will suffice:
lis = ['h','e','l','l','','','','','o','','','','w']
output = [v for i, v in enumerate(lis) if v != '' or i == 0 or (v == '' and lis[i-1] != '')]
print(output)
This will print:
['h', 'e', 'l', 'l', '', 'o', '', 'w']
You can use a list comprehension with enumerate
and select only those '' which
follow non-empty characters themselves
[c for i, c in enumerate(lis) if c or (not c and lis[i - 1])]
You can use itertools. The idea here is to group according whether strings are empty, noting bool('') == False.
from itertools import chain, groupby
L = (list(j) if i else [''] for i, j in groupby(lis, key=bool))
res = list(chain.from_iterable(L))
print(res)
['h', 'e', 'l', 'l', '', 'o', '', 'w']
You can simply use zip() within a list comprehension as following:
In [21]: lis = ['', '', 'h','e','l','l','','','','','o','','','','w', '', '']
In [22]: lis[:1] + [j for i, j in zip(lis, lis[1:]) if i or j]
Out[22]: ['', 'h', 'e', 'l', 'l', '', 'o', '', 'w', '']
In this case we're looping over each pair an keeping the second item if one of the items in our pair is valid (not empty). You just then need to add the first item to the result because it's omitted.
Why not just a for loop?
new_list = []
for char in lis:
if char == '' and new_list[-1] == '': continue
new_list.append(char)
Outputs
['h', 'e', 'l', 'l', '', 'o', '', 'w']

Python: merge first list with each list within list

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']]

Categories

Resources