Reputation: 7494
Given are a list
list_ = [a,a,b,b,b,a,b,a,b,b,...,b]
and two other lists
l_a = [v1,v2,...,vN]
l_B = [w1,w2,...,wN].
The first element of list_ is always "a
". The remaining elements can be mixed up between being "a
" and "b
" in any random way.
Now, starting from the first element in list_ (which is always "a"):
l_a
until you hit a "b
" (in this case: [v1,
v2]). Form "v1+v2
" as a key for a dictionary (the corresponding value is in step 2. below). This is our current key.w1 + w2 + w3
" as value under the current key.Of course, there is a lot of loop stuff going on that I tried, but it just quickly gets difficult to bookkeep and makes me think there is a better way than nesting loops.
Question: So, simply put, how do I do this in an efficient way?
Thank you
Upvotes: 2
Views: 76
Reputation: 132138
Maybe this will give you some ideas.
What you really want to do is group together the repeated items (itertools.groupby is great for that) then remove the items from the head of the list (you could also leave the lists alone and just maintain an index of your current position and do slicing).
import itertools
import random
import collections
choices = ['a', 'b']
list_ = [random.choice(choices) for _ in range(30)]
l_a = collections.deque([random.randint(1, 100) for _ in range(list_.count('a'))])
l_b = collections.deque([random.randint(1, 100) for _ in range(list_.count('b'))])
# Everything above is to build up the sample data.
# You can wrap your existing l_a, l_B lists in a collections.deque
# make a dictionary that holds the two dequeues keyed by the character we find in list_
lists_by_char = {'a': l_a, 'b': l_b}
# print it out to make sure we aren't cheating
print(list_)
print(l_a)
print(l_b)
for k, g in itertools.groupby(list_):
# k will be the letter 'a' or 'b'
# g will be the items in a _grouper. We can call list on that to get the actual items. But what we care about is the length of that list.
items = [lists_by_char.get(k).popleft() for _ in range(len(list(g)))]
# The we call popleft on the deque matching our current character as many times as our list of characters is long.
print(k, items)
Example output - will vary each time you run it
['a', 'a', 'b', 'b', 'b', 'a', 'a', 'a', 'b', 'a', 'b', 'b', 'a', 'b', 'b', 'b', 'a', 'a', 'a', 'a', 'a', 'b', 'b', 'a', 'a', 'b', 'b', 'b', 'a', 'a']
deque([36, 61, 7, 17, 25, 76, 2, 72, 15, 33, 1, 53, 54, 49, 29, 68])
deque([55, 95, 97, 24, 72, 14, 54, 98, 91, 98, 57, 56, 40, 17])
a [36, 61]
b [55, 95, 97]
a [7, 17, 25]
b [24]
a [76]
b [72, 14]
a [2]
b [54, 98, 91]
a [72, 15, 33, 1, 53]
b [98, 57]
a [54, 49]
b [56, 40, 17]
a [29, 68]
Upvotes: 3
Reputation: 18663
Here's a reasonably simple solution:
# given
a = "A"
b = "B"
l = [a,a,b,b,b,a,b,a,b,b,b] # ['A', 'A', 'B', 'B', 'B', 'A', 'B', 'A', 'B', 'B', 'B']
l_a = range(0, 2*len(l), 2) # [0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20]
l_b = range(1, 2*len(l)+1, 2) # [1, 3, 5, 7, 9, 11, 13, 15, 17, 19, 21]
d = {}
making_l_a_key = True
making_l_b_val = False
key = ()
value = []
for index, item in enumerate(l):
if item == a and making_l_b_val:
making_l_a_key = True
making_l_b_val = False
d[tuple(key)] = value
key = ()
value = []
if item == b and making_l_a_key:
making_l_a_key = False
making_l_b_val = True
if item == a and making_l_a_key:
key += (l_a[index], )
if item == b and making_l_b_val:
value.append(l_b[index])
d[key] = value
print d
Output:
{(10,): [13], (0, 2): [5, 7, 9], (14,): [17, 19, 21]}
Upvotes: 0
Reputation: 15206
Another similar approach:
list_ = "aabbbababbb"
n_a = [len(x) for x in list_.split('b') if x!='']
n_b = [len(x) for x in list_.split('a') if x!='']
This will give you the numbers of consecutive a
's and b
's. You can then use that to sum over and create your keys. Note: using np.cumsum(zip(n_a ,n_b))
should give you the relevant indices to sum over.
Upvotes: 0