MathGroup Archive 1998

[Date Index] [Thread Index] [Author Index]

Search the Archive

RE: Request for help: working with multi-level lists

  • To: mathgroup at smc.vnet.net
  • Subject: [mg13667] RE: [mg13665] Request for help: working with multi-level lists
  • From: "Ersek, Ted R" <ErsekTR at navair.navy.mil>
  • Date: Sat, 15 Aug 1998 04:39:03 -0400
  • Sender: owner-wri-mathgroup at wolfram.com

kcconnolly at aol.com  wrote:
_____________________________
I have a list of 10 elements, each of which is a list of three elements
(let's say in each case an integer, a real number, and a string). I am
looking for the most elegant way to select those first-level elements
(i.e., the lists) whose integer element is equal to a particular value
(let's say "1"), and then to obtain the mean of the real number
elements of the lists selected.  This seems as if it should be simple,
but everything I try leads to Part specification errors.  Any help
would be greatly appreciated.
______________________________

You want to avoid programs that take elements out of a list or matrix
and use those elements to make a new list.  This is often the first
thing new users think of, but it's inefficient to do this (with a long
list) using Mathematica.  Consider (lst) below.

In[1]:=
lst={{1,0.84787,"text"},{1,0.4739,"text"},
{1,0.4108,"text"},{1,0.0771,"text"},
{2,0.7565,"text"},{0,0.0842,"text"},
{1,0.2260,"text"},{0,0.2148,"text"},
{4,0.8246,"text"},{1,0.6548,"text"},
{3,0.7183,"text"},{1,0.7181,"text"},
{1,0.9862,"text"},{0,0.5956,"text"}, {1,0.4053,"text"}};


Either of the lines below work very well for finding all the elements
that have the integer (1) as the first element.  I happen to think the
line that uses Cases is much more readable.  An important point is that
with Select you get a list of elements that make a test come out true. 
With Cases you get a list of elements that match a pattern.

In[2]:=
selected=Select[lst, Part[#,1]===1&];

In[3]:=
selected=Cases[lst,{1,_,_}];


Now that you have a list of all elements with the first part being the
integer (1), you need to make a list of the real numbers in the second
part. A few choices are given below.

In[4]:=
reals=Part[Transpose[selected],2];

In[5]:=
reals=Map[Part[#,2]&, selected];

If you find the code for In[5] cryptic you could use the code in the
next line.  The only down side is that you have to use a global
variable (ie. element2) that may get in your way at sometime.  also the
less cryptic version isn't as concise.

In[6]:=
element2[expr_]:=Part[expr,2]
reals=Map[element2, selected];

In[8]:=
reals=selected/.{int_,rel_,str_}:>rel;

I like the code at In[8] best.  It's very readable, and pretty fast too.
Once you have a list of real numbers it's there is one way to compute
the mean that stands out as most elegant.  I give two versions of it. 
First the longhand version, then the equivalent shorthand version.

In[9]:=
avr=Apply[Plus,reals]/Length[reals]

Out[9]=
0.533341


In[10]:=
avr=Plus@@reals/Length at reals

Out[10]=
0.533341


Warning:
I caution you against using {int_,rel_,str_}->rel  at In[8] above. Why? 
Suppose you give (rel) a value early during your session and then  use
it in a pattern for (lhs->rhs) as below. Then you will get the wrong
result as I did below.

In[11]:=
rel=23;

....
....
....

In[87]:=
reals=p/.{int_,rel_,str_}->rel

Out[87]=
{23,23,23,23,23,23,23,23,23}


If you are thinking about using (lhs->rhs) with a pattern in (lhs) it's
much safer to use 
(lhs:>rhs).


Ted Ersek


  • Prev by Date: Re: Request for help: working with multi-level lists
  • Next by Date: Re: recursive relation problem ?
  • Previous by thread: Re: Request for help: working with multi-level lists
  • Next by thread: Re: Request for help: working with multi-level lists