[Date Prev] [Date Next] [Thread Prev] [Thread Next] Date Index Thread Index Search archive:
Date:Mon, 23 Feb 2004 15:40:23 +0000 (UTC) 
Subject:Re: counting elements in lists 
From:David Young 
Volume-ID: 

On Mon, 23 Feb 2004, Ian Morgan wrote:

> i have a list within lists i.e. [[N V N ADJ] [N V V ADJ] [N ADV N
> V]] (please ignore the grammatical meanings!) and i need to assess
> which element occurs most often for each position, so return one
> list.

The kind of well-defined problem it's hard to resist!

> ... I do have a "pseudo" way of doing it however it is quite
> undignified in the way it goes about it, i.e. lots of for loops etc.
> In general is there an easy way to do this, like a built in pop11
> procedure that i havent managed to find?

I doubt if there is a built-in procedure or if there is an easy way. My
first shot at it is below. Whether it's any more dignified that your own
approach I don't know! It works correctly on your example. In general a
hash table approach might be more efficient than the sorting method for
finding the commonest element of a list.

---

define commonest1(l) -> e;
    ;;; commonest element of a list, assuming contents all words,
    ;;; mishaps if list empty
    if null(l) then
        mishap(0, 'Non-empty list expected')
    endif;
    sort(l) -> l;  ;;; use syssort if needs to be more general
    lvars i, iold = 0, nmax = 0, n = 0;
    for i in l do
        if i /== iold then
            if n > nmax then
                iold -> e;
                n -> nmax;
            endif;
            i -> iold;
            1 -> n;
        else
            n + 1 -> n
        endif
    endfor;
    if n > nmax then
        iold -> e
    endif
enddefine;

define switch_sublists(ll) -> ll2;
    ;;; Changes a list of lists like [[1 2] [3 4]] into
    ;;; one like [[1 3] [2 4]]. Assumes all sublists same
    ;;; length.
    lvars l, e, newll, newl;
    [] -> ll2;
    while not(null(hd(ll))) do
        [] ->> newll -> newl;
        for l in ll do
            dest(l) -> (e, l);
            l :: newll -> newll;
            e :: newl -> newl;
        endfor;
        ncrev(newll) -> ll;
        ncrev(newl) :: ll2 -> ll2;
    endwhile;
    ncrev(ll2) -> ll2
enddefine;

define commonest(ll) /* -> l */;
    ;;; Returns list of commonest elements of sublists of ll
    maplist(switch_sublists(ll), commonest1)
enddefine;

---

David