cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 
Choose Language Hide Translation Bar
TWE
TWE
Level III

Summary with String_Aggregation

HI,

How can I code a table which:

- grouped based on characters and

- build the corresponding cells with conact_items (e.g. separated with ,).

- like the SQL code "SELECT sex, String_Agg(Name,', ') as ConcatName FROM 'Big Class'" GROUP BY sex

 

I know this would be possible with looping but I was wondering if there is another and more elegant way.

 

Based on the "Big Class" table, the result should look like this:

 

sex     ConcatName

f         KATIE, LOUISE, ....
m       TIM, JAMES, ...

 

Many thanks

3 ACCEPTED SOLUTIONS

Accepted Solutions
ih
Super User (Alumni) ih
Super User (Alumni)

Re: Summary with String_Aggregation

It seems like the tabulate platform needs a concatenate summary function.  Here is one way using a single loop on each row of a summary table:

 

Names default to here(1);

dt = Open("$Sample_data/big class.jmp");

//Table with each unique sex and count
dtSum = (dt << Tabulate(
	Add Table( Row Table( Grouping Columns( :sex ) ) )
)) << Make Into Data Table;

//blank column for concatenated names
dtSum << New Column("Names", Character, "Nominal");

//loop for each row/sex
for each row(dtSum,

	// Use Eval and eval expression to insert the sex of the current 
	// row into the where expression of the other table
	Eval(Eval Expr(
	
		//fill in the names one row at a time, joining all values together
		:Names = char( Concat Items(
			
			//get names from main table matching the sex of the summary table
			dt:name[ dt << Get Rows Where( dt:sex == Expr(:sex) ) ],
			","
		) )
	))
);

 

 

View solution in original post

ms
Super User (Alumni) ms
Super User (Alumni)

Re: Summary with String_Aggregation

Here's an attempt using JSL (JMP 15). It can be done interactively too, using transform and combine columns.

dt = Open( "$SAMPLE_DATA/Big Class.jmp" );
dt1 = dt << Transpose( columns( :name ), By( :sex ), Output Table( "Test" ) );
dt1 << Combine Columns(
	delimiter( ", " ),
	Columns( 3 :: N Col( dt1 ) ),
	Selected Columns are Indicator Columns( 0 ),
	Column Name( "ConcatName" )
) << deletecolumns( 2, 4 :: N Col( dt1 ) );

View solution in original post

Jeff_Perkinson
Community Manager Community Manager

Re: Summary with String_Aggregation

@ih and @ms have given you good answers but I was already working on this solution, so I thought I'd post it to show another way to do this, via JSL.

 

Taking advantage of the Subset By option in Subset we can get a table for each subgroup, and then get the values from the Name column and use Concat Items() to build the string of names.

 

dt = Open( "$SAMPLE_DATA/Big Class.jmp" );

dt_list = dt << Subset(
	By( :sex ),
	All rows,
	Selected columns only( 0 ),
	columns( :name, :age, :height, :weight ),
	private
);

nt = New Table();
group_col_name = Word( 1, dt_list[1] << get name, "=" );
nt << New Column( group_col_name, character );
nt << New Column( "concat name" );
nt << add rows( N Items( dt_list ) );
For( i = 1, i <= N Items( dt_list ), i++,
	Column( nt, group_col_name )[i] = Word( 2, dt_list[i] << get name, "= " );
	nt:concat name[i] = Concat Items( dt_list[i]:name << get values, ", " );
);

For( i = 1, i <= N Items( dt_list ), i++,
	Close( dt_list[1], nosave )
);

dt_list = Empty();
-Jeff

View solution in original post

8 REPLIES 8
ih
Super User (Alumni) ih
Super User (Alumni)

Re: Summary with String_Aggregation

It seems like the tabulate platform needs a concatenate summary function.  Here is one way using a single loop on each row of a summary table:

 

Names default to here(1);

dt = Open("$Sample_data/big class.jmp");

//Table with each unique sex and count
dtSum = (dt << Tabulate(
	Add Table( Row Table( Grouping Columns( :sex ) ) )
)) << Make Into Data Table;

//blank column for concatenated names
dtSum << New Column("Names", Character, "Nominal");

//loop for each row/sex
for each row(dtSum,

	// Use Eval and eval expression to insert the sex of the current 
	// row into the where expression of the other table
	Eval(Eval Expr(
	
		//fill in the names one row at a time, joining all values together
		:Names = char( Concat Items(
			
			//get names from main table matching the sex of the summary table
			dt:name[ dt << Get Rows Where( dt:sex == Expr(:sex) ) ],
			","
		) )
	))
);

 

 

TWE
TWE
Level III

Re: Summary with String_Aggregation

Thanks ih,

I tried your approach with some tables and all are working. Sometimes it needed a bit time (depends on the table size).

ms
Super User (Alumni) ms
Super User (Alumni)

Re: Summary with String_Aggregation

Here's an attempt using JSL (JMP 15). It can be done interactively too, using transform and combine columns.

dt = Open( "$SAMPLE_DATA/Big Class.jmp" );
dt1 = dt << Transpose( columns( :name ), By( :sex ), Output Table( "Test" ) );
dt1 << Combine Columns(
	delimiter( ", " ),
	Columns( 3 :: N Col( dt1 ) ),
	Selected Columns are Indicator Columns( 0 ),
	Column Name( "ConcatName" )
) << deletecolumns( 2, 4 :: N Col( dt1 ) );
TWE
TWE
Level III

Re: Summary with String_Aggregation

Thanks ms,

this is a very fast way. I tried it based an huge LogFile and it works in seconds!

Jeff_Perkinson
Community Manager Community Manager

Re: Summary with String_Aggregation

@ih and @ms have given you good answers but I was already working on this solution, so I thought I'd post it to show another way to do this, via JSL.

 

Taking advantage of the Subset By option in Subset we can get a table for each subgroup, and then get the values from the Name column and use Concat Items() to build the string of names.

 

dt = Open( "$SAMPLE_DATA/Big Class.jmp" );

dt_list = dt << Subset(
	By( :sex ),
	All rows,
	Selected columns only( 0 ),
	columns( :name, :age, :height, :weight ),
	private
);

nt = New Table();
group_col_name = Word( 1, dt_list[1] << get name, "=" );
nt << New Column( group_col_name, character );
nt << New Column( "concat name" );
nt << add rows( N Items( dt_list ) );
For( i = 1, i <= N Items( dt_list ), i++,
	Column( nt, group_col_name )[i] = Word( 2, dt_list[i] << get name, "= " );
	nt:concat name[i] = Concat Items( dt_list[i]:name << get values, ", " );
);

For( i = 1, i <= N Items( dt_list ), i++,
	Close( dt_list[1], nosave )
);

dt_list = Empty();
-Jeff
ms
Super User (Alumni) ms
Super User (Alumni)

Re: Summary with String_Aggregation

I wasn't aware of that Subset( By()...) returns a list. Can be very useful. Thanks Jeff!

 

/Marcus

TWE
TWE
Level III

Re: Summary with String_Aggregation

Thanks Jeff,

your solution is also working fast and I was also not aware of of the Subset(by()) command.

TWE
TWE
Level III

Re: Summary with String_Aggregation

Thanks to all approaches.

All of them are working well!