Reputation: 23
Let's consider that I have a list like the following one:
myList = [
'1000', 'ParameterName=Device type', 'ObjectType=0x7', 'DataType=0x7',
'AccessType=ro', 'PDOMapping=0', 'ObjFlags=1', 'ParameterValue=0x00020192',
'1001', 'ParameterName=Error register', 'ObjectType=0x7', 'DataType=0x5',
'AccessType=ro', 'PDOMapping=0', 'ObjFlags=1', 'ParameterValue=0x00',
'1003', 'SubNumber=6', 'ParameterName=Error history', 'ObjectType=0x8'
]
My split points will be '1000'
, '1001'
and '1003'
where the objective is to have
listoflists = [
['1000', 'ParameterName=Device type', 'ObjectType=0x7', 'DataType=0x7',
'AccessType=ro', 'PDOMapping=0', 'ObjFlags=1', 'ParameterValue=0x00020192'],
['1001', 'ParameterName=Error register', 'ObjectType=0x7', 'DataType=0x5',
'AccessType=ro', 'PDOMapping=0', 'ObjFlags=1', 'ParameterValue=0x00'],
['1003', 'SubNumber=6', 'ParameterName=Error history', 'ObjectType=0x8']
]
I can easily do it with a simple for loop as follows.
There are some extra checks as I asked for the nominal case but the number can be an hex (so I use is_numeric
) and also it can be with a different format such as 4digit+string (1234sub2
) so I slice the data. The last check is because as I use the is_digit
some hex can be considered data when it is really text but as always that his happens there is an 'DataThatMaybeIsConfusedAsHex = value'
I can discriminate using the '='
.
for value in configurationFileList:
if is_numeric(value[:4]) and counter != 0 and "=" not in value:
# Append the list to the list of lists
configurationFileListForEachIndex.append(tmpList.copy())
# Clear the list
tmpList.clear()
# Append the New Index
tmpList.append(value)
else:
tmpList.append(value)
counter += 1
I would like to ask if there is any 'prettier' and more efficient way of doing this.
Upvotes: 2
Views: 118
Reputation: 346
If my understanding serves me, following is the code I think can work:
indexs = [i for i, v in enumerate(myList) if v.isnumeric()]
listoflists = [myList[prev:cur] for prev,cur in zip(indexs,indexs[1:]+[len(myList)])]
Result:
>>> print(listoflists)
[['1000', 'ParameterName=Device type', 'ObjectType=0x7', 'DataType=0x7', 'AccessType=ro', 'PDOMapping=0', 'ObjFlags=1', 'ParameterValue=0x00020192'], ['1001', 'ParameterName=Error register', 'ObjectType=0x7', 'DataType=0x5', 'AccessType=ro', 'PDOMapping=0', 'ObjFlags=1', 'ParameterValue=0x00'], ['1003', 'SubNumber=6', 'ParameterName=Error history', 'ObjectType=0x8']]
Upvotes: 2
Reputation: 4253
queryable=iter(myList)
listOfList=[]
sublist=[]
for a in queryable:
if (a.isnumeric()==True) & (len(sublist)>0):
listOfList.append(sublist)
sublist=[]
sublist.append(a)
else:
sublist.append(a)
if(len(sublist)>0):
listOfList.append(sublist)
print(listOfList)
Upvotes: 0
Reputation: 18315
from itertools import takewhile
iterator = iter(myList[1:])
pivots = ["1000", "1001", "1003"]
list_of_lists = [[piv] + list(it.takewhile(lambda entry: entry not in pivots, iterator))
for piv in pivots]
itertools.takewhile(predicate, iterator)
, well, takes from the iterator while the predicate is true. In this case predicate is whether the current entry is a pivot or not. In every turn of the list-comprehension, the iterator
is getting exhausted i.e. every turn we get a list of the desired list_of_lists
. The [1:]
slicing when making the iterator from myList
is so that takewhile
can start taking first pivot's entries at the very beginning.
Upvotes: 0
Reputation: 1204
I think this is the prettiest way to do it:
import numpy as np
res_list = [i for i, value in enumerate(myList) if str.isdigit(value) == True]
result = [l.tolist() for l in np.split(myList, res_list)[1:]]
This uses list comprehension and split
function, thus does not need any for
loop.
Upvotes: 0
Reputation: 1
you may be interested in this solution.
myList = ['1000', 'ParameterName=Device type', 'ObjectType=0x7', 'DataType=0x7', 'AccessType=ro', 'PDOMapping=0',
'ObjFlags=1', 'ParameterValue=0x00020192', '1001', 'ParameterName=Error register', 'ObjectType=0x7',
'DataType=0x5', 'AccessType=ro', 'PDOMapping=0', 'ObjFlags=1', 'ParameterValue=0x00', '1003', 'SubNumber=6',
'ParameterName=Error history', 'ObjectType=0x8']
secondlist = []
secondlist.append(myList)
print(secondlist)
Upvotes: -3
Reputation: 336
I think this is a good candidate for an iterator function:
from typing import Iterator, List
def get_chunks(value: List[str]) -> Iterator[List[str]]:
chunk: List[str] = []
for item in value:
if is_int(item):
# If the value is an integer, we should start a new chunk!
yield chunk
chunk = []
chunk.append(item)
yield chunk # Make sure to yield the remaining chunk at the end
def is_int(value: str) -> bool:
try:
int(value)
return True
except ValueError:
return False
assert list(get_chunks(["100", "foo", "200", "bar"])) == [[], ["100", "foo"], ["200", "bar"]]
To remove outer empty list when the sequence starts with an integer:
list(filter(None, get_chunks(["100", "foo", "200", "bar"])))
# [["100", "foo"], ["200", "bar"]]
One could easily abstract this over the breakpoint condition function (is_int
in this example), making it nicely composable with the various helpers in itertools
.
Upvotes: 2