Swapping the rows and columns in a two dimensional array

Discussion in 'Cadence' started by Suresh Jeevanandam, Aug 4, 2004.

  1. In skill, I have a two dimensional array, and I want to swap the rows
    and columns. Below is something I could come up. But I think there
    should some other simpler and better way. Your suggestion is welcome.

    procedure(lrange(num)
    ;return a list of numbers from 1 to num
    let((rlist)
    rlist = nil
    while(num > 0
    rlist = cons(num rlist)
    num = num-1
    )
    rlist
    ))

    procedure(swapRowCol(aList)
    ;Swap the columns and rows in a two dimensional array
    mapcar(
    lambda( (num)
    mapcar(
    lambda( (row)
    nthelem(num row)
    )
    aList
    )
    )
    lrange(length(aList))
    )
    )

    regards,
    Suresh
     
    Suresh Jeevanandam, Aug 4, 2004
    #1
  2. Suresh,

    First of all, PLEASE do not get lists mixed up with arrays. Lists in SKILL are
    not the same as arrays, and thinking of them as equivalent tends to lead to very
    inefficient programs.

    Why are they different? Well, an array is random access; you can specify an
    index of an array, and the address of the location can be directly computed.
    Lists however are sequential; if you specify an index, then that location is
    found by starting at the beginning of the list and hopping along until you reach
    that index.

    As a result, using functions like nth and nthelem are very slow for large lists,
    especially when executed in a loop, as they have to start from the beginning
    each time.

    Anyway, it sounds as if what you are trying to do is to transpose a list of
    lists. Your code does this, but rather inefficiently, and only for square lists
    of lists (i.e. the length of the list is the same as the length of each
    sublist).

    Compare it with my implementation:

    procedure(abSwapRowCol(aList)
    apply('mapcar cons('list aList))
    )

    Which is:

    a) shorter (by some way ;-> )
    b) more efficient
    c) quite elegant (even if I do say so myself)
    d) handles non-square lists of lists.

    Try:

    a='((1 2 3 4 5) (6 7 8 9 10))
    b='((1 2 3 4) (5 6 7 8) (9 10 11 12) (13 14 15 16))

    and then do abSwapRowCol() on both of threse.

    Regards,

    Andrew.
     
    Andrew Beckett, Aug 4, 2004
    #2
  3. Suresh Jeevanandam

    oghdayan Guest

    For those who (like me ) need a little head scratching to undertand
    Andrew's lisp hacks:
    abSwapRowCol( '((1 2) (3 4)) )
    <->
    mapcar( 'list '(1 2) '(3 4) )

    what happens with non-square lists is murky to me, but it seems mapcar
    simply truncates numrows to length of the smallest sublist. i.e.
    abSwapRowCol( '((1 2) (3 4 5)) )
    returns 2 rows.
     
    oghdayan, Aug 5, 2004
    #3
  4. Indeed. I should have explained that, but it was getting late last night...
    If you have abSwapRowCol('((1 2) (3 4) (5 6) (7 8)) this ends up
    as mapcar('list '(1 2) '(3 4) '(5 6) '(7 8)). mapcar is passed the name of a
    function as the first argument, and then it processes each of the lists in the
    argument list to mapcar in parallel, passing the first element of each list as
    all the arguments to the list() function, and then moving on to the second
    elements, and so on.
    That's a non-rectangular list, not a non-square list. By non-square I meant one
    which had all the sub-lists the same length as each other, but the sub-list
    length being different from the number of sub-lists. Suresh's code didn't work
    with that.

    However, my code will not necessarily work with non-rectangular lists (and if
    you think about it, what would you want it to do). When mapcar is presented with
    multiple lists, they need really to be the same length, but it will cope
    provided that the first list is the shortest. If the first list is not the
    shortest, it will error:

    *Error* mapcar: multiple arg lists should be the same length

    If the lists are uneven, and the first is the shortest (or equal shortest), then
    it will truncate each list to the length of the first.

    However, I think that the expectation here is that these list-of-lists would be
    properly constructed. You could always add a simple check for the lengths being
    equal first if you really wanted:

    let(((len length(car(aList))))
    forall(elem cdr(aList) len==length(elem))
    )

    but of course this slows it down a little if you know your list of lists is
    properly constructed.

    Regards,

    Andrew.
     
    Andrew Beckett, Aug 5, 2004
    #4
  5. Suresh Jeevanandam

    Satya Mishra Guest

    Suresh> In skill, I have a two dimensional array, and I want to
    Suresh> swap the rows and columns. Below is something I could come
    Suresh> up. But I think there should some other simpler and better
    Suresh> way. Your suggestion is welcome.

    Suresh> procedure(lrange(num) ;return a list of numbers from 1
    Suresh> to num let((rlist) rlist = nil while(num > 0 rlist =
    Suresh> cons(num rlist) num = num-1 ) rlist ))

    Suresh> procedure(swapRowCol(aList) ;Swap the columns and rows
    Suresh> in a two dimensional array mapcar( lambda( (num) mapcar(
    Suresh> lambda( (row) nthelem(num row) ) aList ) )
    Suresh> lrange(length(aList)) ) )

    Suresh> regards, Suresh

    If I understood correctly you are trying to do a transpose of a matrix
    that is represented as a list of lists, each sublist being a row of
    the matrix.

    The easiest way to do a transpose in this case is
    (apply 'mapcar 'list matrix)
    where matrix looks something like '((1 2 3) (4 5 6))

    Satya
     
    Satya Mishra, Aug 5, 2004
    #5
Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments (here). After that, you can post your question and our members will help you out.