2

I have a list of values in the form of: [0,1], [0,2], [1,3], [2,4], [3,5], [4,6], [5,7], [7,9].

I would like to iterate through the list starting at [0,1] and if the second character (in this case, 1) is equal to that of the first character of another list element (in this case this would correspond to [1,3], it would go to [1,3] and then [3,5], [5,7] and finally [7,9]. At which point it would start at the second element ([0,2]) and do the same thing, culminating in two lists.

To clarify, the list itself contains values that are both even and odd, unlike the example I show here, so I can't split it based on that.

Any ideas to push me in the right direction with this would be greatly appreciated.

  • 3
    Do you tried some code, that we can see? – Alex Jan 29 '17 at 13:33
  • 2
    What would you do when more than one choice is available? Say the list contains both `[1,3]` and `[1,4]`? – Roland Smith Jan 29 '17 at 13:51
  • to continue the above example, it would run through [0,1] until [7,9] and then start back [0,2] until [4,6] – Laurie Williams Jan 29 '17 at 14:13
  • @LaurieWilliams So, it’s one thing if there are `[0, 1]` and `[0, 2]` at the beginning of the list. But what happens in the case of duplicate first values further inside, e.g. `[0, 1], [1, 2], [1, 3], [2, 4], [3, 5]`? – poke Jan 29 '17 at 16:44
  • I'd like to be able to treat as a node of some sort, so that it would follow [1,2] then return to [1,3] which it could then follow. @poke – Laurie Williams Jan 30 '17 at 12:40
  • You should really post more concrete examples. So in my example, you would want `[0, 1], [1, 2], [2, 4], [1, 3], [3, 5]`? – poke Jan 30 '17 at 12:42
  • You're right; I'll try do that in this post. For you example, that's correct. Here's another example, that is slightly more complex. `lst = [[0, 1], [0, 2], [1, 3], [2, 4], [3, 5], [4, 6], [5, 7], [7, 9], [8, 10], [8, 11], [10, 12], [11, 13], [11, 14], [12, 15], [12, 16], [6, 17], [8, 17]]. ` The output I'd like to achieve would be two lists, one containing: ` [0,1], [1,3], [3,5], [5,7], [7,9] ` and another containing: `[0,2], [2,4], [4,6], [6,8], [8,10], [8,11], [10,12], [11,13], [11,14], [12,15], [12,16], [6,17], [8,17]`. – Laurie Williams Jan 30 '17 at 13:06
  • @LaurieWilliams That example is broken, there is no `[6, 8]` in the input. And why would the output do `[8, 10], [8, 11], [10, …]` iterating the ones with key `8` first before following, but then ignoring that at the end with the `[6, 17]` and the `[8, 17]`? – poke Jan 30 '17 at 14:01
  • @poke Sorry I wrote the order incorrectly. ` [6,8] ` can be omitted from the output and ` [6,17], [8,17] ` would be in their respective positions. – Laurie Williams Jan 30 '17 at 15:58

2 Answers2

1

Here is a recursive solution that attempts to follow the items for as long as possible, taking care of alternate unvisited paths too:

from collections import defaultdict
def split(items):
    # create lookup
    lookup = defaultdict(set)
    for k, v in items:
        lookup[k].add(v)

    results = []
    while sum(map(len, lookup.values())):
        # get first element from remaining items
        first_k = min((k for k in lookup if len(lookup[k])))
        first = first_k, min(lookup[first_k])

        # follow that element
        results.append(follow(first, lookup))

    return results

def follow(item, lookup):
    item_k, item_v = item
    lookup[item_k].remove(item_v)

    result = [item]
    # loop through all follow-up items (if any)
    for next_item in sorted(lookup[item_v]):
        # recursively follow the follow-up item
        result.extend(follow((item_v, next_item), lookup))
    return result

Used lke this:

>>> def test(items):
        for x in split(items):
            print(x)

>>> test([[0,1], [0,2], [1,3], [2,4], [3,5], [4,6], [7,9]])
[(0, 1), (1, 3), (3, 5)]
[(0, 2), (2, 4), (4, 6)]
[(7, 9)]

It ignores paths to items that have already been visited:

>>> test([[0, 1], [1, 2], [4, 3], [2, 5], [5, 1]])
[(0, 1), (1, 2), (2, 5), (5, 1)]
[(4, 3)]

But follows all of them in order when there are multiple ones (sorted, not original order):

>>> test([[0, 1], [1, 2], [1, 3], [2, 4], [3, 5]])
[(0, 1), (1, 2), (2, 4), (1, 3), (3, 5)]

And it works for your complex example too:

>>> test([[0, 1], [0, 2], [1, 3], [2, 4], [3, 5], [4, 6], [5, 7], [7, 9], [8, 10], [8, 11], [10, 12], [11, 13], [11, 14], [12, 15], [12, 16], [6, 8], [8, 17]])
[(0, 1), (1, 3), (3, 5), (5, 7), (7, 9)]
[(0, 2), (2, 4), (4, 6), (6, 8), (8, 10), (10, 12), (12, 15), (12, 16), (8, 11), (11, 13), (11, 14), (8, 17)]
poke
  • 369,085
  • 72
  • 557
  • 602
  • thanks for this idea -- unfortunately the lists will always contain k values which are the same, so I will stay away from a lookup approach. – Laurie Williams Jan 29 '17 at 14:15
  • You’ll still need a lookup. Anyway, here’s an updated version to your clarified requirements. – poke Jan 30 '17 at 14:16
  • Thanks for your help, I'll start getting my head around this. – Laurie Williams Jan 30 '17 at 16:05
  • I'm attempting to add a check function to this so that, for example, `[6,8]` were to be removed from the original list in the complex example, two lists would still be returned as `6` and `8` are linked through a shared value, `17` (as opposed to the multiple that are currently returned). I've added made a couple of changes but can't get it to work -- i;ve updated the original post with the small changes I made. Any insight into where i'm going wrong would be appreciated – Laurie Williams Feb 02 '17 at 13:13
  • @LaurieWilliams Maybe you should create a new question for this since it drastically changes what you want to do, further invalidating the answers due to your edits. – poke Feb 02 '17 at 13:18
0

You can't iterate through the usual way which is using the "for" loop, because for loop can't jump to a specific value. So use a "while" loop. This code finds all the value packs that matches their last and first values. So you can use it for finding matching values from the middle of a complex list too.

listoflists = [[0,1], [0,2], [1,3], [2,4], [3,5], [4,6], [7,9]]

addr0 = 0
addr1 = 0
print len(listoflists)
while addr0 < len(listoflists):
    val0 = listoflists[addr0]
    last_num = val0[1]
    while addr1 < len(listoflists): # Second iteration for finding the matching value
        val1 = listoflists[addr1]
        if val1[0] == last_num:
            print "found: ",listoflists[addr0], listoflists[addr1] # Found the matching values
            addr0 = addr1
            break
        addr1 += 1
    addr0 += 1
Buğra Coşkun
  • 171
  • 3
  • 16