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
|