So... itertools.combinations gives you an iterator (see this):
>>> import itertools
>>> a = [1,2,3,4,5,6]
>>> itertools.combinations(a,2)
<itertools.combinations object at 0x10ca841d8>
Which means that it doesn't put all the possible items in memory until the item itself is requested.
One quick an dirty solution would be only keeping the items that you want. For instance, if you only want to keep pairs whose last item (or pair[1]) is equal to 4, you could do:
>>> pairs = [ pair for pair in itertools.combinations(a,2) if pair[1] == 4 ]
>>> pairs
[(1, 4), (2, 4), (3, 4)]
(assuming that pair[1] is what you call index)
If that's still too big, you might need to implement your own iterator, so you don't pre-load all the items in memory, but rather you calculate them only when requested.
If what you call index is the first item of the pair, you could use this in a similar fashion. For instance, let's say you only want items in which the first item (pair[0]) is equal to 2:
>>> pairs = [ pair for pair in itertools.combinations(a,2) if pair[0] == 2 ]
>>> pairs
[(2, 3), (2, 4), (2, 5), (2, 6)]
That would work... But if this is the case, is probably better if you use itertools.product, like this:
>>> [a for a in itertools.product([2], [5, 6, 7])]
[(2, 5), (2, 6), (2, 7)]
Or use map to apply a function to each item in the iterable...
>>> [a for a in map(lambda x: (2, x), [1, 2, 3])]
[(2, 1), (2, 2), (2, 3)]