I can't imagine I'm going to get much help from this due to my inability to explain it. But for instance I have a string like so:
s = "[1,[2,2,[3,4]],5]"
and I need to convert it into a nested list item as such
lst = ["1",["2","2",["3","4"]],"5"]
that if I were to go lst[1][2][0] it would return '3'.
The way I have tried to do it was by creating a substring for every number within '[' and end of string characters and then slowly nest it back up
def ParseList(strlist):
if '[' in strlist:
print strlist
return ParseList(GetBetweenChar(strlist,'[',None))
else:
return strlist
however it returns:(which although maybe a good start? I dont know where to continue)
[1,[2,2,[3,4]],5]
1,[2,2,[3,4]],5
2,2,[3,4]],
3,4]]
which I would think I would append that to a list item but I dont know how to..
You can use ast.literal_eval to safely convert the string to a nested list of integers. Then define a nested map function to convert to all elements to strings, whilst maintaining the nesting structure.
from ast import literal_eval
s = "[1,[2,2,[3,4]],5]"
ls = literal_eval(s)
# yes I know there is something else called nmap
def nmap(fn, iterable):
res = []
for i in iterable:
if isinstance(i, list): # could be tuple or something else?
res.append(nmap(fn, i))
else:
res.append(fn(i))
return res
result = nmap(str, ls)
print(result)
print(result[1][2][0])
result:
['1', ['2', '2', ['3', '4']], '5']
3
You can use eval(). Just be careful to make sure the string is safe because eval will convert a string to valid python code.
>>> eval("[1,[2,2,[3,4]],5]")[1][2][0]
3
Some more info: What does Python's eval() do?
If you didn't require every piece to be a string, but you could let numbers be numbers, then you can use the json library:
>>> s = "[1,[2,2,[3,4]],5]"
>>> import json
>>> json.loads(s)
[1, [2, 2, [3, 4]], 5]
Notice that if your original list contains numbers or booleans, they will stay as numbers or booleans. This is probably what you want, BUT if you really need everything to be strings, then you can recurse through the nested arrays and apply str to everything (look for "How to do flatmap in Python") or request further help in the comment section below.
You could proceed by first adding the quotes around the digits, then eval the list:
s = "[1,[2,2,[3,4]],5]"
res = ''
for c in s:
if c.isdigit():
res += '"' + c + '"'
else:
res += c
s = eval(res)
s
output:
['1', ['2', '2', ['3', '4']], '5']
This will work for single digit numbers; a little bit more work would be needed for multiple digits, or floats
Eval is not safe for user input.
You can do something like for python (2.6+):
>>> import ast
>>> s = "[1,[2,2,[3,4]],5]"
>>> lst = ast.literal_eval(s)
>>> str(lst[1][2][0])
'3'
Related
For example lets say I have a list as below,
list = ['list4','this1','my3','is2'] or [1,6,'one','six']
So now I want to change the index of each element to match the number or make sense as I see fit (needn't be number) like so, (basically change the index of the element to wherever I want)
list = ['this1','is2','my3','list4'] or ['one',1,'six',6]
how do I do this whether there be numbers or not ?
Please help, Thanks in advance.
If you don't wanna use regex and learn it's mini language use this simpler method:
list1 = ['list4','this1', 'he5re', 'my3','is2']
def mySort(string):
if any(char.isdigit() for char in string): #Check if theres a number in the string
return [float(char) for char in string if char.isdigit()][0] #Return list of numbers, and return the first one (we are expecting only one number in the string)
list1.sort(key = mySort)
print(list1)
Inspired by this answer: https://stackoverflow.com/a/4289557/11101156
For the first one, it is easy:
>>> lst = ['list4','this1','my3','is2']
>>> lst = sorted(lst, key=lambda x:int(x[-1]))
>>> lst
['this1', 'is2', 'my3', 'list4']
But this assumes each item is string, and the last character of each item is numeric. Also it works as long as the numeric parts in each item is single digit. Otherwise it breaks. For the second one, you need to define "how you see it fit", in order to sort it in a logic.
If there are multiple numeric characters:
>>> import re
>>> lst = ['lis22t4','th2is21','my3','is2']
>>> sorted(lst, key=lambda x:int(re.search(r'\d+$', x).group(0)))
['is2', 'my3', 'list4', 'this21']
# or,
>>> ['is2', 'my3', 'lis22t4', 'th2is21']
But you can always do:
>>> lst = [1,6,'one','six']
>>> lst = [lst[2], lst[0], lst[3], lst[1]]
>>> lst
['one', 1, 'six', 6]
Also, don't use python built-ins as variable names. list is a bad variable name.
If you just want to move element in position 'y' to position 'x' of a list, you can try this one-liner, using pop and insert:
lst.insert(x, lst.pop(y))
If you know the order how you want to change indexes you can write simple code:
old_list= ['list4','this1','my3','is2']
order = [1, 3, 2, 0]
new_list = [old_list[idx] for idx in order]
If you can write your logic as a function, you can use sorted() and pass your function name as a key:
old_list= ['list4','this1','my3','is2']
def extract_number(string):
digits = ''.join([c for c in string if c.isdigit()])
return int(digits)
new_list = sorted(old_list, key = extract_number)
This case list is sorted by number, which is constructed by combining digits found in a string.
a = [1,2,3,4]
def rep(s, l, ab):
id = l.index(s)
q = s
del(l[id])
l.insert(ab, q)
return l
l = rep(a[0], a, 2)
print(l)
Hope you like this
Its much simpler
I have a python list that looks like alist = ['4', '1.6', 'na', '2e-6', '42']. If i want to remove the quotes from this and make it look like [4, 1.6, na, 2e-6, 42], normally i use the following code :
alist = [float(x) if type(x) is str else None for x in alist]
But this time, as I have the string 'na' as one of the elements in the list, this line of code will not work. Is there an elegant way to do this in python?
Assuming you are happy to replace the value 'na' with None, or more generally, any non-float looking text with None, then you could do something like:
def converter(x):
try:
return float(x)
except ValueError:
return None
alist = [converter(x) for x in alist]
This will convert anything to float that it can. So, as it stands, this will also convert existing numbers to float:
>>> [converter(x) for x in ('1.1', 2, 'na')]
[1.1, 2.0, None]
When python lists, sets, dicts, etc are printed out, they are printed in the same format that python uses to compile the "raw code." Python compiles lists in quotes. So you just need to iterate over the list.
Simply use a generator expression to fix this (though it really doens't have much effect unless you are displaying on a tkinter widget or something):
>>> alist = ['4', '1.6', 'na', '2e-6', '42']
>>> for a in alist:
... print(a)
>>> 4
>>> 1.6
>>> na
>>> 2e-6
>>> 42
I'm not sure where the "na", "nan" confusion is coming from. Regardless, if you want to lose the quotes, run your code through a generator expression and it will no longer be under the "list class" - hence, the quotes will no longer appear.
The list elements are all still the same type,
edit: clarity, grammar
I have the list it contain int ,float and string:
lists = [10, "test", 10.5]
How Can i convert above list to string? I have tried:
val = ','.join(lists)
print val
I am getting error like this:
sequence item 0: expected string, int found
How can I solve this issue?
Firstly convert integers to string using strusing map function then use join function-
>>> ','.join(map(str,[10,"test",10.5]) )#since added comma inside the single quote output will be comma(,) separated
>>> '10,test,10.5'
Or if you want to convert each element of list into string then try-
>>> map(str,[10,"test",10.5])
>>> ['10', 'test', '10.5']
Or use itertools for memory efficiency(large data)
>>>from itertools import imap
>>>[i for i in imap(str,[10,"test",10.5])]
>>>['10', 'test', '10.5']
Or simply use list comprehension
>>>my_list=['10', 'test', 10.5]
>>>my_string_list=[str(i) for i in my_list]
>>>my_string_list
>>>['10', 'test', '10.5']
The easiest way is to send the whole thing to str() or repr():
>>> lists = [10, "test", 10.5]
>>> str(lists)
"[10, 'test', 10.5]"
repr() may produce a different result from str() depending on what's defined for each type of object in the list. The point of repr() is that you can send such strings back to eval() or ast.literal_eval() to get the original object back:
>>> import ast
>>> lists = [10, "test", 10.5]
>>> ast.literal_eval(repr(lists))
[10, 'test', 10.5]
a = ['b','c','d']
strng = ''
for i in a:
strng +=str(i)
print strng
The error you are getting because join wants elements to be string type, but in your list there is integer too, so 1st you have to convert them to type string.
you can use list comprehension and str and join to join them
>>> lists = [10,"test",10.5]
>>> ",".join(str(x) for x in lists)
You have to pass each item in your list as a string into the ','.join(sequence). Consider using:
val = ','.join([str(item) for item in lists])
print val
If you want to convert each element in the list to a string, you could do it simply using a for-loop.
for i in range(len(lists)):
lists[i] = str(lists[i])
Alternatively, if you want to make one string where all elements are joined together, you could edit the code above slightly.
string_of_lists = ""
for i in lists:
string_of_lists += str(i)
As you can tell, this is another way of doing it, apart from the other solutions using join.
I hope I helped!
This is also possible. Here x variable is list.
>>> '%s'*len(x) % tuple(x)
As mentioned here
list=['a/b/c', 'd/e/f']
file_list_string= ' '.join(list)
file_list_string= ' '.join(str(file) for file in list)
import functools
lists = [10,"test",10.5]
print(functools.reduce(lambda x,y:x+","+y,list(map(str,lists))))
You could always do it the dirty way:
list_name = ["a", "b", "c"];
string_name = "";
for c in list_name:
string_name += c
print(string_name)
OUTPUT:
"abc"
That should work with ints, floats, and strings, always converting them to string type.
How would one answer this foor loop question using proper python syntax:
def int_all_2(str_list):
'''(list of str) -> NoneType
Replace every str element of str_list with its corresponding
int version.
For example,
>>> sl = ['100', '222', '2', '34']
>>> int_all_2(sl)
>>> sl
[100, 222, 2, 34]
'''
Would it be like this?
l = []
for x in str_list:
l.append (int_all_2(x))
return l
If you want to convert each element of the list to integer and then return a new list you can use map function :
def strs2ints(l):
return map(int,l)
You should also note that function strs2ints doesn't change the contents of array l.
In case you want to change the contents of the original array l, which I do not recommend(you should prefer using "clean" functions over functions with side-effects) you can try the following code :
def strs2ints(l):
for i in range(len(l)):
l[i] = int(l[i])
Assuming your list contains only string representation of numeric integers, you don't even need a function, just list comprehension:
l = [int(itm) for itm in str_list]
If you want to ignore possible strings:
l = [int(itm) for itm in str_list if not itm.isalpha]
Or, if you require a function:
def int_all(str_list):
return [int(itm) for itm in str_list]
Is there a pythonic way to insert an element into every 2nd element in a string?
I have a string: 'aabbccdd' and I want the end result to be 'aa-bb-cc-dd'.
I am not sure how I would go about doing that.
>>> s = 'aabbccdd'
>>> '-'.join(s[i:i+2] for i in range(0, len(s), 2))
'aa-bb-cc-dd'
Assume the string's length is always an even number,
>>> s = '12345678'
>>> t = iter(s)
>>> '-'.join(a+b for a,b in zip(t, t))
'12-34-56-78'
The t can also be eliminated with
>>> '-'.join(a+b for a,b in zip(s[::2], s[1::2]))
'12-34-56-78'
The algorithm is to group the string into pairs, then join them with the - character.
The code is written like this. Firstly, it is split into odd digits and even digits.
>>> s[::2], s[1::2]
('1357', '2468')
Then the zip function is used to combine them into an iterable of tuples.
>>> list( zip(s[::2], s[1::2]) )
[('1', '2'), ('3', '4'), ('5', '6'), ('7', '8')]
But tuples aren't what we want. This should be a list of strings. This is the purpose of the list comprehension
>>> [a+b for a,b in zip(s[::2], s[1::2])]
['12', '34', '56', '78']
Finally we use str.join() to combine the list.
>>> '-'.join(a+b for a,b in zip(s[::2], s[1::2]))
'12-34-56-78'
The first piece of code is the same idea, but consumes less memory if the string is long.
If you want to preserve the last character if the string has an odd length, then you can modify KennyTM's answer to use itertools.izip_longest:
>>> s = "aabbccd"
>>> from itertools import izip_longest
>>> '-'.join(a+b for a,b in izip_longest(s[::2], s[1::2], fillvalue=""))
'aa-bb-cc-d'
or
>>> t = iter(s)
>>> '-'.join(a+b for a,b in izip_longest(t, t, fillvalue=""))
'aa-bb-cc-d'
I tend to rely on a regular expression for this, as it seems less verbose and is usually faster than all the alternatives. Aside from having to face down the conventional wisdom regarding regular expressions, I'm not sure there's a drawback.
>>> s = 'aabbccdd'
>>> '-'.join(re.findall('..', s))
'aa-bb-cc-dd'
This version is strict about actual pairs though:
>>> t = s + 'e'
>>> '-'.join(re.findall('..', t))
'aa-bb-cc-dd'
... so with a tweak you can be tolerant of odd-length strings:
>>> '-'.join(re.findall('..?', t))
'aa-bb-cc-dd-e'
Usually you're doing this more than once, so maybe get a head start by creating a shortcut ahead of time:
PAIRS = re.compile('..').findall
out = '-'.join(PAIRS(in))
Or what I would use in real code:
def rejoined(src, sep='-', _split=re.compile('..').findall):
return sep.join(_split(src))
>>> rejoined('aabbccdd', sep=':')
'aa:bb:cc:dd'
I use something like this from time to time to create MAC address representations from 6-byte binary input:
>>> addr = b'\xdc\xf7\x09\x11\xa0\x49'
>>> rejoined(addr[::-1].hex(), sep=':')
'49:a0:11:09:f7:dc'
Here is one list comprehension way with conditional value depending of modulus of enumeration, odd last character will be in group alone:
for s in ['aabbccdd','aabbccdde']:
print(''.join([ char if not ind or ind % 2 else '-' + char
for ind,char in enumerate(s)
]
)
)
""" Output:
aa-bb-cc-dd
aa-bb-cc-dd-e
"""
This one-liner does the trick. It will drop the last character if your string has an odd number of characters.
"-".join([''.join(item) for item in zip(mystring1[::2],mystring1[1::2])])
As PEP8 states:
Do not rely on CPython's efficient implementation of in-place string concatenation for statements in the form a += b or a = a + b. This optimization is fragile even in CPython (it only works for some types) and isn't present at all in implementations.
A pythonic way of doing this that avoids this kind of concatenation, and allows you to join iterables other than strings could be:
':'.join(f'{s[i:i+2]}' for i in range(0, len(s), 2))
And another more functional-like way could be:
':'.join(map('{}{}'.format, *(s[::2], s[1::2])))
This second approach has a particular feature (or bug) of only joining pairs of letters. So:
>>> s = 'abcdefghij'
'ab:cd:ef:gh:ij'
and:
>>> s = 'abcdefghi'
'ab:cd:ef:gh'