cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 
JMP is taking Discovery online, April 16 and 18. Register today and join us for interactive sessions featuring popular presentation topics, networking, and discussions with the experts.
Choose Language Hide Translation Bar
pmroz
Super User

JSL Programming Challenge: Convert from string of Ys and Ns to matrix of 1s and 0s, and back again

Hi JSL programmers,

 

I had a little problem as part of a larger application and thought I'd share it with you, and see if there's a way to do it better/slicker.

Basically I have a vector of 1s and 0s (i.e. [1, 1, 0, 0, 1]) that I need to convert to a string of Ys and Ns (i.e. "YYNNY").  Then I need to do the reverse, that is convert a string of Ys and Ns back to a vector of 1s and 0s.

Here are my quick and dirty functions - let's see if you can come up with something beyond my feeble brainpower!

// Convert a vector of 1s and 0s to a string with no separators
matrix_10_to_yn = function({matrix_10}, {default local},
	yn_txt = "";
	if (nrows(matrix_10) > 0,
// Strip out square brackets and commas
		yn_txt = substitute(char(matrix_10), "[", "", "]", "", ", ", "");
// Now convert 1s to Y and 0s to N
		yn_txt = substitute(yn_txt, "1", "Y", "0", "N");
	);
	yn_txt;
);

// Convert a YN string with no separators to a vector of 1s and 0s 
yn_to_matrix_10 = function({yn_txt}, {default local},
	n = length(yn_txt);
	matrix_10 = j(n, 1, 0);
	for (i = 1, i <= n, i++,
		if (substr(yn_txt, i, 1) == "Y",
			matrix_10[i] = 1;
		);
	);
	matrix_10;
);

// Test thing out a = yn_to_matrix_10("YYYNNNN"); show(a); b = matrix_10_to_yn(a); show(b); c = yn_to_matrix_10(""); show(c); d = matrix_10_to_yn(c); show(d);
5 ACCEPTED SOLUTIONS

Accepted Solutions
gzmorgan0
Super User (Alumni)

Re: JSL Programming Challenge: Convert from string of Ys and Ns to matrix of 1s and 0s, and back aga

Whatever works, works!  Here is one alternative.

 

exmat = J(25,1, RandomInteger(0,1));
exlst = Insert({}, {"Y", "N"}[2-exmat]);

convert_yn = Function({usr}, {rslt, ynList ={"Y","N"} },
 if(IsMatrix(usr), 
	rslt = insert({},ynList[2-usr])
 , //else
     rslt = J(nitems(usr),1, 1);
     rslt[loc(usr,"N")]=0
  );  //end if
  rslt
); //end Function

show(exmat, convert_yn(exmat), exlst, convert_yn(exlst));

 

 

View solution in original post

vince_faller
Super User (Alumni)

Re: JSL Programming Challenge: Convert from string of Ys and Ns to matrix of 1s and 0s, and back aga

Another!!

 

Names Default to here(1);
yto1 = function({str}, 
	{DEFAULT LOCAL}, 
	list = words(str, "");
	design(list, {"Y"});
);
oneToY = function({mat}, 
	list = substitute(as list(mat), 1, "Y", 0, "N");
	Concat items(list, "");
);
str = "YYYNNNNYYNY";
nums = yto1(str);
show(nums);
str2 = oneToY(nums);
show(str2, str2==str);
Vince Faller - Predictum

View solution in original post

Craige_Hales
Super User

Re: JSL Programming Challenge: Convert from string of Ys and Ns to matrix of 1s and 0s, and back aga

 

This won't extend to three values or missing/error values without some extra effort. It converts string--blob--matrix and does the Y and N detection using the number of the ASCII character in the matrix. The BlobToMatrix and MatrixToBlob functions are told to use 1-byte little-endian integers. The endianness is not critical for 1-byte numbers, big works just as well. It does depend on the characters having one byte representations. 

source = "YYNNYQ";
// if you are uncomfortable with hard coded constants...
Yvalue = Blob To Matrix( Char To Blob( "Y" ), "int", 1, "little" )[1]; // 89
Nvalue = Blob To Matrix( Char To Blob( "N" ), "int", 1, "little" )[1]; // 78
// forward
numbers = Blob To Matrix( Char To Blob( source ), "int", 1, "little" ) == Yvalue;
// reverse
string = Blob To Char( Matrix To Blob( Nvalue + numbers * (Yvalue - Nvalue), "int", 1, "little" ) );
// display
Show( source, numbers, string );

source = "YYNNYQ";
numbers = [1, 1, 0, 0, 1, 0];
string = "YYNNYN";

 

Craige

View solution in original post

MathStatChem
Level VI

Re: JSL Programming Challenge: Convert from string of Ys and Ns to matrix of 1s and 0s, and back aga

you can do the string to matrix conversion in a single line using Char to Blob and Blob to Matrix. My contribution: 

names default to here(1);

a=[1,0, 1, 1, 1, 0, 0, 1, 0, 1];
b="YNYYYNNYNY";

f_YNString_to_IndicatorVector=Function({s},
	blob to matrix(char to blob(d),"int", 1, "little", 1)==89;
);

f_IndicatorVector_to_YNString=Function({v},{vv},
	vv=As List(v);
	vv[loc(v)]="Y";
	vv[loc(!v)]="N";
	concat items(vv,"");
);

show(a);
show(b);
Show(f_YNString_to_IndicatorVector(b));
Show(f_IndicatorVector_to_YNString(a));
Show(f_IndicatorVector_to_YNString(f_YNString_to_IndicatorVector(b)));


View solution in original post

gzmorgan0
Super User (Alumni)

Re: JSL Programming Challenge: Convert from string of Ys and Ns to matrix of 1s and 0s, and back aga

These are all very cool solutions. PMROZ pointed out that I misread that the secanrio is to start with a list. He asked for my revised solution.  Below converts a list or a string of YN's to a vector of 10's and a vector of 10's to a string of YN's.

 

To be consistent with my previous post, I just converted the string to a list with the words() function using an empty string delimiter.

 

exmat = J(25,1, RandomInteger(0,1));
exlst = Insert({}, {"Y", "N"}[2-exmat]);
exstr = ConcatItems(Insert({}, {"Y", "N"}[2-exmat]), "");

convert_yn = Function({usr}, {rslt=empty(), ynList ={"Y","N"} },
 if(IsMatrix(usr), 
	rslt = ConcatItems(insert({},ynList[2-usr]),"")
 , //else
    IsList(usr),
     rslt = J(nitems(usr),1, 1);
     rslt[loc(usr,"N")]=0
 , //else
    IsString(usr),
     rslt = J(length(Trim(usr)),1,1);
     rslt[loc(words(usr,""),"N")]=0    
  );  //end if
  rslt
); //end Function

show(exmat, convert_yn(exmat), exlst, convert_yn(exlst), exstr, convert_yn(exstr) );

View solution in original post

11 REPLIES 11
gzmorgan0
Super User (Alumni)

Re: JSL Programming Challenge: Convert from string of Ys and Ns to matrix of 1s and 0s, and back aga

Whatever works, works!  Here is one alternative.

 

exmat = J(25,1, RandomInteger(0,1));
exlst = Insert({}, {"Y", "N"}[2-exmat]);

convert_yn = Function({usr}, {rslt, ynList ={"Y","N"} },
 if(IsMatrix(usr), 
	rslt = insert({},ynList[2-usr])
 , //else
     rslt = J(nitems(usr),1, 1);
     rslt[loc(usr,"N")]=0
  );  //end if
  rslt
); //end Function

show(exmat, convert_yn(exmat), exlst, convert_yn(exlst));

 

 

vince_faller
Super User (Alumni)

Re: JSL Programming Challenge: Convert from string of Ys and Ns to matrix of 1s and 0s, and back aga

Another!!

 

Names Default to here(1);
yto1 = function({str}, 
	{DEFAULT LOCAL}, 
	list = words(str, "");
	design(list, {"Y"});
);
oneToY = function({mat}, 
	list = substitute(as list(mat), 1, "Y", 0, "N");
	Concat items(list, "");
);
str = "YYYNNNNYYNY";
nums = yto1(str);
show(nums);
str2 = oneToY(nums);
show(str2, str2==str);
Vince Faller - Predictum
Craige_Hales
Super User

Re: JSL Programming Challenge: Convert from string of Ys and Ns to matrix of 1s and 0s, and back aga

 

This won't extend to three values or missing/error values without some extra effort. It converts string--blob--matrix and does the Y and N detection using the number of the ASCII character in the matrix. The BlobToMatrix and MatrixToBlob functions are told to use 1-byte little-endian integers. The endianness is not critical for 1-byte numbers, big works just as well. It does depend on the characters having one byte representations. 

source = "YYNNYQ";
// if you are uncomfortable with hard coded constants...
Yvalue = Blob To Matrix( Char To Blob( "Y" ), "int", 1, "little" )[1]; // 89
Nvalue = Blob To Matrix( Char To Blob( "N" ), "int", 1, "little" )[1]; // 78
// forward
numbers = Blob To Matrix( Char To Blob( source ), "int", 1, "little" ) == Yvalue;
// reverse
string = Blob To Char( Matrix To Blob( Nvalue + numbers * (Yvalue - Nvalue), "int", 1, "little" ) );
// display
Show( source, numbers, string );

source = "YYNNYQ";
numbers = [1, 1, 0, 0, 1, 0];
string = "YYNNYN";

 

Craige
MathStatChem
Level VI

Re: JSL Programming Challenge: Convert from string of Ys and Ns to matrix of 1s and 0s, and back aga

you can do the string to matrix conversion in a single line using Char to Blob and Blob to Matrix. My contribution: 

names default to here(1);

a=[1,0, 1, 1, 1, 0, 0, 1, 0, 1];
b="YNYYYNNYNY";

f_YNString_to_IndicatorVector=Function({s},
	blob to matrix(char to blob(d),"int", 1, "little", 1)==89;
);

f_IndicatorVector_to_YNString=Function({v},{vv},
	vv=As List(v);
	vv[loc(v)]="Y";
	vv[loc(!v)]="N";
	concat items(vv,"");
);

show(a);
show(b);
Show(f_YNString_to_IndicatorVector(b));
Show(f_IndicatorVector_to_YNString(a));
Show(f_IndicatorVector_to_YNString(f_YNString_to_IndicatorVector(b)));


MathStatChem
Level VI

Re: JSL Programming Challenge: Convert from string of Ys and Ns to matrix of 1s and 0s, and back aga

Oops, I didn't see Craig's reply...his version is better, I think.

pmroz
Super User

Re: JSL Programming Challenge: Convert from string of Ys and Ns to matrix of 1s and 0s, and back aga

Wow these are amazing.  Thanks all!

Craige_Hales
Super User

Re: JSL Programming Challenge: Convert from string of Ys and Ns to matrix of 1s and 0s, and back aga

and now I need to study the design() function!

Craige
uday_guntupalli
Level VIII

Re: JSL Programming Challenge: Convert from string of Ys and Ns to matrix of 1s and 0s, and back aga

@pmroz
         Here is my take/attempt at this. Thanks for offering this interesting challenge. I know I am using a loop which I don't know if it will scale well over large matrices, but I thought, some others in the community can come up with a faster way. 

 

Clear Log(); Clear Globals(); 

ex = Associative Array({1,0} ,{"Y", "N"});

Test = [1,0, 1, 1, 1, 0, 0, 1, 0, 1];

Res = {}; 

for(i = 1, i <= N Rows(Test), i++,
		Insert Into(Res, ex << Get Value(Test[i])); 
   ); 

Show(Res);


Best
Uday
ih
Super User (Alumni) ih
Super User (Alumni)

Re: JSL Programming Challenge: Convert from string of Ys and Ns to matrix of 1s and 0s, and back aga

I use a generic 'mapply' function in most projects, so normally I would only need the last two lines:

Names Default to here(1);

// Utility function to make for loops, combo 'map' and 'apply'
// this is a 'fake' map/apply function because it allows side
// effects (like apply) and it also returns a value (like map)
mapply = function( {x, foo, arg1 = "__missing", arg2 = "__missing"}, { i, r = {}, x, foo, arg1, arg2, arg1missing, arg2missing },
	if( N Items( x ) < 1,
		return({}), //empty list supplied, return an empty list
		for( i = 1, i <= N Items(x), i++,
			arg1missing = 0; arg2missing = 0;
			If( type(arg1) == "String", If( arg1 == "__missing", arg1missing = 1 ) );
			If( type(arg2) == "String", If( arg2 == "__missing", arg2missing = 1 ) );
			if( 
				arg1missing == 1,
				r = Insert( r, foo( x[i] ) ),
				arg2missing == 1,
				r = Insert( r, foo( x[i], arg1 ) ),
				r = Insert( r, foo( x[i], arg1, arg2 ) )
			)
		)
	);
	return(r);
);

// Solution:
str = "YYYNNNNYYNY";
(numbers = mapply( words(str,""), function( {x}, if( x=="Y", 1, 0) ) ) )
mapply( as list(numbers), function( {x}, if( x==1,"Y", "N") ) )