How do I find a value relative to where a list occurs within my list in Python?
<p>I have a list of numbers:</p>

<pre><code>Data = [0,2,0,1,2,1,0,2,0,2,0,1,2,0,2,1,1,...]
</code></pre>

<p>And I have a list of tuples of two, which is all possible combinations of the individual numbers above:</p>

<pre><code>Combinations = [(0,0),(0,1),(0,2),(1,0),(1,1),(1,2),(2,0),(2,1),(2,2)]
</code></pre>

<p>I want to try to find where each item in Combinations appears in Data and add the value after each occurrence to another list.</p>

<p>For example, for (0,2) I want to make a list [0,0,0,1] because those are the the values that fall immediately after (0,2) occurs in Data.</p>

<p>So far, I have:</p>

<pre><code>any(Data[i:i+len(CurrentTuple)] == CurrentTuple for i in xrange(len(Data)-len(CurrentTuple)+1))
</code></pre>

<p>Where <code>CurrentTuple</code> is <code>Combinations.pop()</code>. 
The problem is that this only gives me a Boolean of whether the <code>CurrentTuple</code> occurs in Data. What I really need is the value after each occurrence in Data.</p>

<p>Does anyone have any ideas as to how this can be solved? Thanks!</p>

<p>You can use a dict to group the data to see where/if any comb lands in the original list zipping up pairs:</p>

<pre><code>it1, it2 = iter(Data), iter(Data)
next(it2)

Combinations = [(0, 0), (0, 1), (0, 2), (1, 0), (1, 1), (1, 2), (2, 0), (2, 1), (2, 2)]

d = {c: [] for c in Combinations}
ind = 2
for i, j in zip(it1, it2):
    if (i, j) in d and ind &lt; len(Data):
        d[(i, j)].append(Data[ind])
    ind += 1
print(d)
</code></pre>

<p>Which would give you:</p>

<pre><code>{(0, 1): [2, 2], (1, 2): [1, 0], (0, 0): [], (2, 1): [0, 1], (1, 1): [2], (2, 0): [1, 2, 1, 2], (2, 2): [], (1, 0): [2], (0, 2): [0, 0, 0, 1]}
</code></pre>

<p>You could also  do it in reverse:</p>

<pre><code>from collections import defaultdict

it1, it2 = iter(Data), iter(Data)
next(it2)
next_ele_dict = defaultdict(list)
data_iter = iter(Data[2:])
for ind, (i, j) in enumerate(zip(it1, it2)):
    if ind &lt; len(Data) -2:
      next_ele_dict[(i, j)].append(next(data_iter))

def next_ele():
    for comb in set(Combinations):
        if comb in next_ele_dict:
           yield comb, next_ele_dict[comb]

print(list(next_ele()))
</code></pre>

<p>Which would give you:</p>

<pre><code> [((0, 1), [2, 2]), ((1, 2), [1, 0]), ((2, 1), [0, 1]), ((1, 1), [2]), ((2, 0), [1, 2, 1, 2]), ((1, 0), [2]), ((0, 2), [0, 0, 0, 1])]
</code></pre>

<p>Any approach is better than a pass over the Data list for every element in Combinations.</p>

<p>To work for arbitrary length tuples we just need to create the tuples based on the length:</p>

<pre><code>from collections import defaultdict

n = 2

next_ele_dict = defaultdict(list)

def chunks(iterable, n):
    for i in range(len(iterable)-n):
        yield tuple(iterable[i:i+n])

data_iter = iter(Data[n:])
for tup in chunks(Data, n):
      next_ele_dict[tup].append(next(data_iter))

def next_ele():
    for comb in set(Combinations):
        if comb in next_ele_dict:
            yield comb, next_ele_dict[comb]


print(list(next_ele()))
</code></pre>

<p>You can apply it to whatever implementation you prefer, the logic will be the same as far as making the tuples goes.</p>

python list tuples markov-chains