Search code examples
pythonlistappendmultiple-columnsfinite-element-analysis

Write multi columns list on the fly


Hi i am writing a list as follow:

> l = [[10312, -13.069404602050781], [10313, -28.044403076171875],
>      [10314, -32.765602111816406], [10315, -47.353294372558594],
>      [10312, -63.069404602050781], [10313, -78.044403076171875],
>      [10314, -82.765602111816406], [10315, -97.353294372558594]]

as you can see from line 3 the first item of the list get repeated, what i am trying to achieve is that a soon as the loop reaches maxCount, instead of keep appending at the bottom of the list, it appends on the right. what i would ideally like to obtain is:

 l = [[10312, -13.069404602050781, -63.069404602050781], 
      [10313, -28.044403076171875, -78.044403076171875],
      [10314, -32.765602111816406, -82.765602111816406], 
      [10315, -47.353294372558594, -97.353294372558594]]

any ideas?

I have came up with a solution, but I feel a bit limited, I am using now a list of list generator, like this

 table=[]
     for k in range(0, len(elementContainer):
         k = []
         table.append(k)

I thought to you a dictionary generator but could not get it to work, any help or if you have a better solution.


Solution

  • This does the job, if I undesrtood correctly:

    l = [[10312, -13.069404602050781], [10313, -28.044403076171875],
         [10314, -32.765602111816406], [10315, -47.353294372558594],
         [10312, -63.069404602050781], [10313, -78.044403076171875],
         [10314, -82.765602111816406], [10315, -97.353294372558594]]
    
    from pprint import pprint
    d = {}
    
    for i,(x,n) in enumerate(l):
        print i,x,n
        if x in d:
            l[d[x]].append(n)
            del l[i][:]
        else:
            d[x] = i
    
    l = filter(None,l)
    
    pprint (l)
    

    .

    Edit

    Here's a better algorithm because there's no more the filtering of the list done by the instruction l = filter(None,l) , so the transformation is in-place.

    This instruction l = filter(None,l) creates a new list, that is to say a new object at another address in the memory: then the above code don't realize an in-place transformation of the list.
    The following one performs such an in-place transformation, as it is put in evidence by the printing of the identities (id est addresses) of the list l before and after its treatment.

    l = [[10312, -13.069404602050781],
         [10313, -28.044403076171875],
         [10314, -32.765602111816406],
         [10312, -63.069404602050781, -55.4444],
         [20666, -91, -92, -93, -94],
         [10315, -47.353294372558594],
         [10314, -82.765602111816406],
         [10315, -97.353294372558594],
         [10313, -78.044403076171875],
         [20666, -40.33, -94, -50.33, -91, -93]
         ]
    
    from pprint import pprint
    d = {}
    to_del = []
    print 'id(l) before : ',id(l)
    pprint (l)
    
    for i,subli in enumerate(l):
        if subli[0] in d:
            d[subli.pop(0)].extend(subli)
            to_del.insert(0,i)
        else:
            d[subli[0]] = subli
    
    for i in to_del:
        del l[i]
        
    print '\nid(l) after  : ',id(l)
    pprint (l)
    
    • Note that in the former code, the values of d were the indexes of the sublists of l.
      Now in this new code, the values of d are directly the sublists of l.
      It is more pythonic to reference objects directly, instead of referecing them indirectly through their indexes in the list whose they are elements of.

    • The list to_del records the indexes of the sublists that will be deleted after the first loop. Each index added is inserted at the beginning of to_del (not appended to it) so that the second loop ( for i in to_del )will run retrogressively through the list l , which is the condition that must be respected when elements of a list are deleted on the basis of their indexes.

    The instruction d[subli.pop(0)].extend(subli) may seem somewhat a little difficult to understand.

    The operations begins with the execution of subli.pop(0) : this instruction triggers the extraction of the element indexed 0 from the sublist subli and returns it.
    Then d[subli.pop(0)] furnishes the object subli.pop(0) to d as a key, meanwhile this objects is removed from the sublist subli.
    So, at this point, the sublist subli has been shortened of its first element, as if the instruction subli[:] = subli[1:] had been performed see remark at the bottom.

    Next, the sublist d[subli.pop(0)] , that had been precedently encountered in l during the iteration through list l , is extended with the elements remaining in the sublist subli after this one has been shortened, that is to say with the elements that were indexed 1 to len(subli)-1 BEFORE it was shortened. But, as subli has been shortened, we only write subli, not subli[1:].

    And it works ! Result:

    id(l) before :  18732936
    [[10312, -13.069404602050781],
     [10313, -28.044403076171875],
     [10314, -32.765602111816406],
     [10312, -63.06940460205078, -55.4444],
     [20666, -91, -92, -93, -94],
     [10315, -47.353294372558594],
     [10314, -82.7656021118164],
     [10315, -97.3532943725586],
     [10313, -78.04440307617188],
     [20666, -40.33, -94, -50.33, -91, -93]]
    
    id(l) after  :  18732936
    [[10312, -13.069404602050781, -63.06940460205078, -55.4444],
     [10313, -28.044403076171875, -78.04440307617188],
     [10314, -32.765602111816406, -82.7656021118164],
     [20666, -91, -92, -93, -94, -40.33, -94, -50.33, -91, -93],
     [10315, -47.353294372558594, -97.3532943725586]]
    

    .

    If you want that only non-redudant elements be added to a previously existing sublist, it must be:

    for i,subli in enumerate(l):
        print 1,subli
        if subli[0] in d:
            precsubli = d[subli.pop(0)]
            precsubli.extend(el for el in subli
                             if el not in precsubli)
            to_del.insert(0,i)
        else:
            d[subli[0]] = subli
    

    .

    Important remark

    Note the difference :

    N = [10000,2,3,4]
    
    initial_id = id(N)
    print initial_id, N
    
    N = N[1:]
    
    print id(N), N
    print '%d==%d : %s' %\
          (initial_id, id(N), initial_id==id(N) )
    
    print '------------------'
    
    A = ['HEY','b','c','d']
    
    initial_id = id(A)
    print initial_id, A
    
    A[:] = A[1:]
    
    print id(A), A
    print '%d==%d : %s' %\
          (initial_id, id(A), initial_id==id(A) )
    

    result

    18669480 [10000, 2, 3, 4]
    11868480 [2, 3, 4]
    18669480==11868480 : False
    ------------------
    18731816 ['HEY', 'b', 'c', 'd']
    18731816 ['b', 'c', 'd']
    18731816==18731816 : True
    

    That means that A is modified in-place, while object referenced by N is not: the instruction N[1:] builds a new object, at a location in the memory elsewhere than the location of the object referenced by N.