zingy
zingy

Reputation: 811

comparing and replacing the elements of a nested list

I have got a list which is:

mylist = {
           'a': [(-1,-1), (0.2,0.4)] 
           'b': [(0.3,1.0), (-1,-1)]
           'c': [(-1,-1), (-1,-1)]
           'd': [(0.15,0.35), (0.05,0.15)]
          }

I have to get an output which will be like the following:

 mylist = {
           'a': [(0.3, 0.35), (0.2,0.4)] 
           'b': [(0.3,0.35), (0.05,0.15)]
           'c': [(0.15,0.35), (0.05,0.15)]
           'd': [(0.15,0.35), (0.05,0.15)]
          }

The list above looks like this when I print it,

mylist = [ ('a', [ (-1, -1), (0.2, 0.4) ] ), 
           ('b', [ (0.3, 1.0), (-1, -1) ] ), 
           ('c', [ (-1, -1), (-1, -1) ] ), 
           ('d', [ (0.15, 0.35), (0.05, 0.15) ] ) ]

Now the algorithm is like the following:

1st iteration: Compare a[0] and b[0] ie (-1, -1) and (0.3, 1.0). 
               Here replace (-1, -1) by (0.3, 1.0). 
               Rule: (-1, -1) is considered as empty or not in use so 
                     it gets replaced while comparison. 

               Similarly, compare a[1] and b[1] ie (0.2, 0.4) and (-1, -1). 
               Here keep the same value as b[1] is empty so no change. 

               Hence the new elements of 'a' are (0.3, 1.0), (0.2, 0.4). 
               Rule: if comparing with empty one then keep the same values.

2nd iteration: Compare new values of a[0] and c[0] ie (0.3, 1.0) and (-1, -1). 
               Here again no change. 
               Similarly, compare new values of a[1] and c[1] ie (0.2, 0.4) and (-1, -1).
               Here also no change. 
               Now the new elements of 'a' are (0.3, 1.0), (0.2, 0.4).

This process carries till 'a' is compared to the last element in the list here its upto 'd'. Then comes the turn of 'b' and same thing will continue between 'b' and 'c' then 'b and 'd' and so on.

The other rules when comparison between two actual ranges (0.1,0.3) and (0.5,1.0).

Say if two ranges totally overlap like (0.1, 0.8) and (0.3, 0.9) then, it should take the common between them which is (0.3, 0.8).

If they don't overlap like (0.1, 0.4) and (0.5, 0.9) then, it should choose its own which is (0.1, 0.4).

And if they partially overlap then also take the common between them. Like (0.4, 1.0) and (0.8, 1.5) then it should choose (0.8, 1.0).

P.S. The values (0.2, 0.4) are the ranges actually indicating the actual value will vary between 0.2 to 0.4. I think now I have explained a bit more clearly. Thank you

Upvotes: 0

Views: 794

Answers (1)

agf
agf

Reputation: 176750

def update(mylist, row, col, cmprow, cmpcol):
    lo, hi = mylist[row][col]
    low, high = mylist[cmprow][cmpcol]

    # always replace the current value if it's (-1, -1)
    if (lo, hi) == (-1, -1):
        mylist[row][col] = low, high
        print "replacing empty", row, col, "with", cmprow, cmpcol
        return

    # never replace the current value if the ranges don't overlap
    # or the other range is (-1, -1)
    if (low, high) == (-1, -1) or lo >= high or hi <= low:
        print row, col, "doesn't overlap", cmprow, cmpcol
        return

    # set the low to the highest low and the high to the lowest high
    print "updating", row, col, "with", cmprow, cmpcol
    mylist[row][col] = max((lo, low)), min((hi, high))



def update_ranges(oldlist):
    # make a copy of the list as we're going to modify it
    mylist = oldlist[:]
    # we don't need the row titles, they just complicate things
    rowtitles, mylist = zip(*mylist)
    rows = len(mylist)
    columns = range(len(mylist[0]))

    # for each row except the last
    for i in xrange(rows - 1):
        # update it by going down all the rows below it
        for k in xrange(i+1, rows):
            # for both columns
            for j in columns:
                update(mylist, i, j, k, j)

    # put the row titles back in
    mylist = zip(rowtitles, mylist)
    return mylist



def test():
    oldlist = [ ('a', [ (-1, -1), (0.2, 0.4) ] ),
               ('b', [ (0.3, 1.0), (-1, -1) ] ),
               ('c', [ (-1, -1), (-1, -1) ] ),
               ('d', [ (0.15, 0.35), (0.05, 0.15) ] ) ]
    print "Original List"
    print '\n'.join(str(l) for l in oldlist)
    newlist = update_ranges(oldlist)
    print "New List"
    print '\n'.join(str(l) for l in newlist)

if __name__ == '__main__':
    test()

Edit: Updated update_ranges to work for any number of columns.

Upvotes: 1

Related Questions