BookmarkSubscribeRSS Feed
Choose Language Hide Translation Bar
Jaz
Jaz
Community Trekker

How to Separate Matching Values in a List

Hi,

 

I have a list which could contain the following, for example: {22, 22, 22, 33, 33}. I want to be able to get the number of each unique value in the list, e.g. the number of 22's and the number of 33's. The problem is, I don't know how long my list will be and how many unique numbers there will be in the list. Is there any way in JSL to generalise a solution for this?

 

Thanks

0 Kudos
1 ACCEPTED SOLUTION

Accepted Solutions
Highlighted
pmroz
Super User

Re: How to Separate Matching Values in a List

Table operations are probably the fastest way to do this.

my_list = {22, 22, 22, 33, 33};
dt = New Table( "Untitled", invisible, Add Rows( nitems(my_list) ),
	New Column( "Column 1", Numeric, "Continuous", Format( "Best", 12 ),
		Set Values( my_list )
	)
);
dtab = dt << Tabulate(Show Control Panel( 0 ),
	Add Table( Row Table( Grouping Columns( :Column 1 ) ) ));
dt2 = dtab << Make Into Data Table(invisible);
unique_value_list = dt2:column 1 << get values;
unique_count      = dt2:n << get values;
close(dt, nosave);
close(dt2, nosave);
show(unique_value_list, unique_count);
16 REPLIES 16
Jaz
Jaz
Community Trekker

Re: How to Separate Matching Values in a List

I've managed to get a list of the unique values like so {22, 33} using associative arrays and the << get key functionality but I still don't know how to get the number of each of those unique values in the original list.

0 Kudos
Highlighted
pmroz
Super User

Re: How to Separate Matching Values in a List

Table operations are probably the fastest way to do this.

my_list = {22, 22, 22, 33, 33};
dt = New Table( "Untitled", invisible, Add Rows( nitems(my_list) ),
	New Column( "Column 1", Numeric, "Continuous", Format( "Best", 12 ),
		Set Values( my_list )
	)
);
dtab = dt << Tabulate(Show Control Panel( 0 ),
	Add Table( Row Table( Grouping Columns( :Column 1 ) ) ));
dt2 = dtab << Make Into Data Table(invisible);
unique_value_list = dt2:column 1 << get values;
unique_count      = dt2:n << get values;
close(dt, nosave);
close(dt2, nosave);
show(unique_value_list, unique_count);
txnelson
Super User

Re: How to Separate Matching Values in a List

Here is my variation on @pmroz solution.  It is more of an old school solution

my_list = {22, 22, 22, 33, 33};
dt = New Table( "Untitled",
	private,
	Add Rows( N Items( my_list ) ),
	New Column( "Column 1",
		Numeric,
		"Continuous",
		Format( "Best", 12 ),
		Set Values( my_list )
	)
);
// Use the Summary Platform to create the aggragate values
dtSum = dt << Summary(
	private,
	Group( :Column 1 ),
	Freq( "None" ),
	Weight( "None" )
);
// Create the new lists
unique_value_list = As List( dtSum:column 1 << get values );
unique_count = As List( dtSum:n rows << get values );
Close( dt, nosave );
Close( dtSum, nosave );
Show( unique_value_list, unique_count );
Jim
pmroz
Super User

Re: How to Separate Matching Values in a List

Don't forget summarize.  Even shorter.

my_list = {22, 22, 22, 33, 33};
dt = New Table( "Untitled", invisible, Add Rows( nitems(my_list) ),
	New Column( "Column 1", Numeric, "Continuous", Format( "Best", 12 ),
		Set Values( my_list )
	)
);

summarize(dt, unique_value_list = by(:column1), unique_count = count(:column 1) );
show(unique_value_list, unique_count);
vince_faller
Super User

Re: How to Separate Matching Values in a List

@pmroz's response got me interested.  Because I usually try to avoid data tables if I can just because of the overhead.  I played with timings

 

names default to here(1);
my_list = {44, 33, 22, 33, 44};

repeat_list = [1, 5, 10, 50, 100, 1000,  2500, 5000, 7500, 10000];
dt_timing = new table("Timings", 
	new column("List Size"), 
	new column("Design"), 
	new column("Loop"), 
	new column("Summarize"), 
);
for(ii=1, ii<=20, ii++, 
	for(ir = 1, ir <= nitems(repeat_list), ir++, 
		my_bigger_list = repeat(my_list, repeat_list[ir]);


		// using design
		st = HPTime();
		aa = associative array(my_bigger_list);
		keys = aa << Get Keys;
		d = design(my_bigger_list, keys);
		aa_design = associative array(keys, VSum(d));
		time_design = HPTime() - st;


		//using a loop
		st = HPTime();
		aa_loop = associative array(my_bigger_list, repeat(0, nitems(my_bigger_list)));
		for(i=1, i<=nitems(my_bigger_list), i++, 
			aa_loop[my_bigger_list[i]]++;
		);
		time_loop = HPTime() - st;


		//using a data table
		st = HPTime();
		dt = New Table( "Untitled", invisible, Add Rows( nitems(my_bigger_list) ),
			New Column( "Column 1", Numeric, "Continuous", Format( "Best", 12 ),
				Set Values( my_bigger_list )
			)
		);

		summarize(dt, unique_value_list = by(:column1), unique_count = count(:column 1) );
		close(dt, nosave);

		aa_peter = associative array(unique_value_list, unique_count);
		time_peter = HPTime()-st;
		Eval(EvalExpr(
			dt_timing << Add Rows({List Size = Expr(Nitems(my_bigger_list)), Design = Expr(time_design), Loop = Expr(time_loop), Summarize = Expr(time_peter)});
		));

	);
);


dt_stack = dt_timing << Stack(
	columns( :Design, :Loop, :Summarize ),
	Source Label Column( "Method" ),
	Stacked Data Column( "Timing" )
);

close(dt_timing, no save);

biv = dt_stack << Bivariate(
	Y( :Timing ),
	X( :List Size ),
	group by(:Method),
	fit line(), 
	SendToReport(
		Dispatch(
			{},
			"Bivar Plot",
			FrameBox,
			{Row Legend(
				Method,
			)}
		),
	)
);

 

and obviously it depends on the list size.  But I ran it 20 times each on various list sizes and got this

timing.png

 

Design was the fastest way I could find to do it.  And I definitely agree with @txnelson that I don't like Summarize because of it returning character always.  

 

 

Vince Faller - Predictum
Jeff_Perkinson
Community Manager Community Manager

Re: How to Separate Matching Values in a List

I agree with @pmroz and @txnelson, data tables make this easy.

 

I prefer the Summarize() function over Tabulate and Summary for this though.

 

 

my_list = {22, 22, 22, 33, 33};
dt = New Table( "Untitled",
	private,
	Add Rows( N Items( my_list ) ),
	New Column( "Column 1",
		Numeric,
		"Continuous",
		Format( "Best", 12 ),
		Set Values( my_list )
	)
);

summarize(dt, group=by(:column 1), n=count(:column 1));

show(group, n);

 

 

 

-Jeff
txnelson
Super User

Re: How to Separate Matching Values in a List

My support for the Summary Platform, is that the grouping variable is maintained as the same Data Type in the summary data table as it was in the originating data table.  In the Summarize() function, it is always returned as character values, even if the By column specified was numeric.

Jim
Jaz
Jaz
Community Trekker

Re: How to Separate Matching Values in a List

Thanks,

 

Would be useful if JMP included a find matching items / return matching items function for lists / associative arrays as they do for columns & rows.

0 Kudos

Re: How to Separate Matching Values in a List

Please post this suggestion in the Wish List area of the Community.

Learn it once, use it forever!
0 Kudos