def convert_to_list(VertexList):
VerticesList = []
items = VertexList.split(';')
for item in items:
i = item.split(',')
SubList = []
for item in i:
SubList.append(item)
VerticesList.append(SubList)
return VerticesList
This code converts string in this format to a 2D list. However, I am sure it can be optimized.
Input -> '1,2,4,5,6,7;2,3,4,5,6,7,8;1,2,4,5,6,8'
Output -> [['1', '2', '4', '5', '6', '7'], ['2', '3', '4', '5', '6', '7', '8'], ['1', '2', '4', '5', '6', '8']]
Use a comprehension.
inp = '1,2,4,5,6,7;2,3,4,5,6,7,8;1,2,4,5,6,8'
print([s.split(',') for s in inp.split(';')])
Results in
[['1', '2', '4', '5', '6', '7'], ['2', '3', '4', '5', '6', '7', '8'], ['1', '2', '4', '5', '6', '8']]
This is smaller, easier to read code, which is part of the optimization I expect you were looking for. It doesn't loop through things any fewer times, but it's executing fewer assignments, using less temporary variabels, and making fewer function calls (i.e. append()). Maybe some of those calls are being made behind the scenes in the comprehension, but you should be taking advantage of whatever optimizations Python does to its comprehensions in terms of what functions calls are made.
--update--
Check out this answer for a performance analysis of the OP and this answer.
-- update 2 --
To convert all strings to int, you can use map or another comprehension.
inp = '1,2,4,5,6,7;2,3,4,5,6,7,8;1,2,4,5,6,8'
print([list(map(int, s.split(','))) for s in inp.split(';')])
or
inp = '1,2,4,5,6,7;2,3,4,5,6,7,8;1,2,4,5,6,8'
print([[int(c) for c in s.split(',')] for s in inp.split(';')])
This is not a solution, but only a comparison of the optimality of the above codes in terms of actual performance:
from timeit import Timer
code1 = """\
def convert_to_list(VertexList):
VerticesList = []
items = VertexList.split(';')
for item in items:
i = item.split(',')
SubList = []
for item in i:
SubList.append(item)
VerticesList.append(SubList)
return VerticesList
inp = '1,2,4,5,6,7;2,3,4,5,6,7,8;1,2,4,5,6,8'
convert_to_list(inp)
"""
code2 = """\
inp = '1,2,4,5,6,7;2,3,4,5,6,7,8;1,2,4,5,6,8'
out = [s.split(',') for s in inp.split(';')]
"""
t = Timer(stmt=code1)
time1 = t.timeit() # 1000000 iteration by default
print(f"Original time:{round(time1, 6)} sec.")
t = Timer(stmt=code2)
time2 = t.timeit() # 1000000 iteration by default
print(f"New time: {round(time2, 6)} sec.")
print(f'New solution faster in = {round(time1 / time2, 1)} times')
Output:
Original time:1.812856 sec.
New time: 0.741987 sec.
New solution faster in = 2.4 times
Related
I am trying t convert a number as follows:
input -> 123456
output -> ['1','2','3','4','5','6']
The following loop does work:
number = 123456
defg = []
abc = str(number)
for i in range(len(abc)):
defg.append(abc[i])
However, when i try this in the form of a one line for loop, the output is ['None','None','None','None']
My one line loop is as follows:
number = 123456
defg = []
abc = str(number)
defg= [[].append(abc[i]) for i in range(len(abc))]
Any idea what I am doing wrong?
The answers above are concise, but I personally prefer vanilla list comprehension over map, as powerful as it is. I add this answer simply for the sake of adding diversity to the mix, showing that the same can be achieved without using map.
str_list = [abc[i] for i in range(len(abc))]
We can strive for a more Pythonic solution by avoiding direct indexing and using a simpler loop.
better_str_list = [char for char in abc]
This list comprehension is basically just a translation of the for loop you already have.
Try this:
x = 527876324
print(list(str(x))
Output
['5', '2', '7', '8', '7', '6', '3', '2', '4']
here the solution
list(map(lambda x: str(x), str(number)))
Out[13]: ['1', '2', '3', '4', '5', '6']
or you can do this
list(map(str, str(number)))
Out[13]: ['1', '2', '3', '4', '5', '6']
or this
list(str(number))
['1', '2', '3', '4', '5', '6']
duplicate you can see more here
Splitting integer in Python?
Solution
As your expection the result is
number = 123456
defg = []
abc = str(number)
[defg.append(abc[i]) for i in range(len(abc))]
print(defg)
When you run the loop the values are append to defg but it return none. you assign the None value to defg so it will show the None output
Recomanded way
You can use list metnod to convert the number to list
number = 865393410
result = list(str(number))
print(result)
If you want int in list try this
number = 865393410
result = []
for i in list(str(number)):
result.append(int(i))
print(result)
With single line loop
number = 865393410
result = []
[result.append(int(i)) for i in list(str(number))]
print(result)
The last one is recommended for you
i have list like
list = ['1,2,3,4,5', '6,7,8,9,10']
I have problem with "," in list, because '1,2,3,4,5' its string.
I want to have list2 = ['1','2','3','4'...]
How i can do this?
Should be something like that:
nums = []
for str in list:
nums = nums + [int(n) for n in str.split(',')]
You can loop through and split the strings up.
list = ['1,2,3,4,5', '6,7,8,9,10']
result = []
for s in list:
result += s.split(',')
print(result)
Split each value in the original by , and then keep appending them to a new list.
l = []
for x in ['1,2,3,4,5', '6,7,8,9,10']:
l.extend(y for y in x.split(','))
print(l)
Use itertools.chain.from_iterable with map:
from itertools import chain
lst = ['1,2,3,4,5', '6,7,8,9,10']
print(list(chain.from_iterable(map(lambda x: x.split(','), lst))))
# ['1', '2', '3', '4', '5', '6', '7', '8', '9', '10']
Note that you shouldn't use list name for variables as it's a built-in.
You can also use list comprehension
li = ['1,2,3,4,5', '6,7,8,9,10']
res = [c for s in li for c in s.split(',') ]
print(res)
#['1', '2', '3', '4', '5', '6', '7', '8', '9', '10']
list2 = []
list2+=(','.join(list).split(','))
','.join(list) produces a string of '1,2,3,4,5,6,7,8,9,10'
','.join(list).split(',') produces ['1', '2', '3', '4', '5', '6', '7', '8', '9', '10']
join method is used to joined elements in a list by a delimiter. It returns a string in which the elements of sequence have been joined by ','.
split method is used to split a string into a list by a delimiter. It splits a string into an array of substrings.
# Without using loops
li = ['1,2,3,4,5', '6,7,8,9,10']
p = ",".join(li).split(",")
#['1', '2', '3', '4', '5', '6', '7', '8', '9', '10']
I am having a list which contains some elements with repetition and from this list I want to generate a list which has no repeated elements in it AND also maintains theie Order in the List.
I tried set(['1','1','2','3','4','4','5','2','2','3','3','6']) and got the output as set(['1', '3', '2', '5', '4', '6'])
But I want the output as set(['1', '2', '3', '4', '5', '6']) i.e. maintain the relative order of the elements already present.
How to do this??? Thanks in advance...
One way to do this:
In [9]: x = ['1','1','2','3','4','4','5','2','2','3','3','6']
In [10]: s = set()
In [11]: y = []
In [12]: for i in x:
...: if i not in s:
...: y.append(i)
...: s.add(i)
...:
In [13]: y
Out[13]: ['1', '2', '3', '4', '5', '6']
As noted by Martijn, a set is unordered by definition, so you need a list to store the result. See also this old question.
Starting with two lists such as:
lstOne = [ '1', '2', '3', '4', '5', '6', '7', '8', '9', '10']
lstTwo = [ '1', '2', '3', '4', '5', '6', '7', '8', '9', '10']
I want to have the user input how many items they want to extract, as a percentage of the overall list length, and the same indices from each list to be randomly extracted. For example say I wanted 50% the output would be
newLstOne = ['8', '1', '3', '7', '5']
newLstTwo = ['8', '1', '3', '7', '5']
I have achieved this using the following code:
from random import randrange
lstOne = [ '1', '2', '3', '4', '5', '6', '7', '8', '9', '10']
lstTwo = [ '1', '2', '3', '4', '5', '6', '7', '8', '9', '10']
LengthOfList = len(lstOne)
print LengthOfList
PercentageToUse = input("What Percentage Of Reads Do you want to extract? ")
RangeOfListIndices = []
HowManyIndicesToMake = (float(PercentageToUse)/100)*float(LengthOfList)
print HowManyIndicesToMake
for x in lstOne:
if len(RangeOfListIndices)==int(HowManyIndicesToMake):
break
else:
random_index = randrange(0,LengthOfList)
RangeOfListIndices.append(random_index)
print RangeOfListIndices
newlstOne = []
newlstTwo = []
for x in RangeOfListIndices:
newlstOne.append(lstOne[int(x)])
for x in RangeOfListIndices:
newlstTwo.append(lstTwo[int(x)])
print newlstOne
print newlstTwo
But I was wondering if there was a more efficient way of doing this, in my actual use case this is subsampling from 145,000 items. Furthermore, is randrange sufficiently free of bias at this scale?
Thank you
Q. I want to have the user input how many items they want to extract, as a percentage of the overall list length, and the same indices from each list to be randomly extracted.
A. The most straight-forward approach directly matches your specification:
percentage = float(raw_input('What percentage? '))
k = len(data) * percentage // 100
indicies = random.sample(xrange(len(data)), k)
new_list1 = [list1[i] for i in indicies]
new_list2 = [list2[i] for i in indicies]
Q. in my actual use case this is subsampling from 145,000 items. Furthermore, is randrange sufficiently free of bias at this scale?
A. In Python 2 and Python 3, the random.randrange() function completely eliminates bias (it uses the internal _randbelow() method that makes multiple random choices until a bias-free result is found).
In Python 2, the random.sample() function is slightly biased but only in the round-off in the last of 53 bits. In Python 3, the random.sample() function uses the internal _randbelow() method and is bias-free.
Just zip your two lists together, use random.sample to do your sampling, then zip again to transpose back into two lists.
import random
_zips = random.sample(zip(lstOne,lstTwo), 5)
new_list_1, new_list_2 = zip(*_zips)
demo:
list_1 = range(1,11)
list_2 = list('abcdefghij')
_zips = random.sample(zip(list_1, list_2), 5)
new_list_1, new_list_2 = zip(*_zips)
new_list_1
Out[33]: (3, 1, 9, 8, 10)
new_list_2
Out[34]: ('c', 'a', 'i', 'h', 'j')
The way you are doing it looks mostly okay to me.
If you want to avoid sampling the same object several times, you could proceed as follows:
a = len(lstOne)
choose_from = range(a) #<--- creates a list of ints of size len(lstOne)
random.shuffle(choose_from)
for i in choose_from[:a]: # selects the desired number of items from both original list
newlstOne.append(lstOne[i]) # at the same random locations & appends to two newlists in
newlstTwo.append(lstTwo[i]) # sequence
So, I was doing Project Euler 37
I need to circulate a list
input: 2345 # converted to list inside function
expected output: [[3,4,5,2],[4,5,2,3],[5,2,3,4],[2,3,4,5]]
Here is my function for that
def circulate(n): #2345
lst=list(str(n)) #[2,3,4,5]
res=[]
for i in range(len(lst)):
temp=lst.pop(0)
lst.append(temp)
print lst #print expected list
res.append(lst) #but doesn't append as expected
return res
print circulate(2345)
My output is:
['3', '4', '5', '2']
['4', '5', '2', '3']
['5', '2', '3', '4']
['2', '3', '4', '5']
[['2', '3', '4', '5'], ['2', '3', '4', '5'], ['2', '3', '4', '5'], ['2', '3', '4', '5']]
The function prints lst correct every time, but doesn't append as expected.
What I am doing wrong?
You need to append copies of your list to res:
res.append(lst[:])
You were appending a reference to the list being altered instead; all references reflect the changes made to the one object.
You may want to look at collections.deque() instead; this double-ended list object supports efficient rotation with a .rotate() method:
from collections import deque
def circulate(n):
lst = deque(str(n))
res = []
for i in range(len(lst)):
lst.rotate(1)
res.append(list(lst))
return res