BookmarkSubscribeRSS Feed
🔒 This topic is solved and locked. Need further help from the community? Please sign in and ask a new question.
silversta
Calcite | Level 5

Hello!

 

I am attempting to create a variable in my data that is the sum of the characters in a string (comprised of 0s and 1s). The code below does sum the 1s in the string, but I'm not sure how to manipulate it to provide the information that I'm looking for. For those whose strings start with 1s and change to 0s, that is ok. For those whose strings start with 0, regardless of the 1s that may follow, those need to be set to 0. Lastly, for those whose strings have 0s in the middle of the 1s, I need to only sum the 1s before it hits the 0. I apologize if this seems confusing and have tried to provide an illustration below of the string and the sum that I would like to calculate. Any help would be most appreciated!

 

x_all                                 sum that code below calculates        sum that I want

1111111000000                            6                                                   6                     

0000001111111                            7                                                   0           

1111000111111                            10                                                  4

 

data want (drop = i );
set have;
x_total=0;
do i=1 to length(x_all);
x_total+input(substr(x_all,i,1),1.);
end;

1 ACCEPTED SOLUTION

Accepted Solutions
novinosrin
Tourmaline | Level 20

HI @silversta  If I understand you correctly, it's a simple boolean expression.

 


data have;
input x_all :$20.;*                                 sum that code below calculates        sum that I want;
cards;
1111111000000                            6                                                   6                     
0000001111111                            7                                                   0           
1111000111111
;

data want;
 set have;
 want=(verify(x_all,'1')>1)*(verify(x_all,'1')-1);
run;

View solution in original post

22 REPLIES 22
novinosrin
Tourmaline | Level 20

HI @silversta  If I understand you correctly, it's a simple boolean expression.

 


data have;
input x_all :$20.;*                                 sum that code below calculates        sum that I want;
cards;
1111111000000                            6                                                   6                     
0000001111111                            7                                                   0           
1111000111111
;

data want;
 set have;
 want=(verify(x_all,'1')>1)*(verify(x_all,'1')-1);
run;
biopharma
Quartz | Level 8
Hi @novinosrin,

Nice solution.

Wondering whether this would be sufficient?

want = verify(x_all,'1')-1 ;

novinosrin
Tourmaline | Level 20

Yes indeed. Good catch. I'll have to be a more diligent like you are. Thank you!

novinosrin
Tourmaline | Level 20

Hi @biopharma  I just showed my mother(a retired banker) how elegantly you made it more terse. However she thinks it's better to have boolean 1 capture in case of missings and value not padded with blank i.e if incoming data is equivalent to something like  stripped(x_all) a missing value the risk of having -1 in the result is apparent, albeit I'd still vote  opposing my mom's thoughts for the reason that occurence is less likely.

 

I can't generally win against her if there's even a remote chance, so it appears the following is what she means. lol

data have;
input x_all :$20.;*                                 sum that code below calculates        sum that I want;
cards;
1111111000000                            6                                                   6                     
0000001111111                            7                                                   0           
1111000111111
.
;

data want;
 set have;
 want=(verify(strip(x_all),'1')-1);
 want1=(verify(strip(x_all),'1')>1)*(verify(strip(x_all),'1')-1);
run;

Fun stuff:)

Tom
Super User Tom
Super User

In general with VERIFY() you have to control for the case when the value being passed is completely filled with valid values.  In that case the result returned will be zero, not the length of the string.  So when you are using it to to find the last valid value, like in this case, you can just append some invalid character to the end of the string you pass it.  As long are your input string is not exactly 32,767 bytes long it should do what you want.

want = verify(x_all || ' ','1')-1 ;

 

novinosrin
Tourmaline | Level 20

I agree. It's a very tricky function yet a very classy one. 

biopharma
Quartz | Level 8
Your Mom rocks! However remote the possibility, it may still be a good idea to program defensively.
silversta
Calcite | Level 5
Worked like a charm, thank you!
silversta
Calcite | Level 5

Hello @novinosrin,

 

Thanks again for the code, it was most helpful! Is there a way to modify it to sum through a string of 1 or 2 0s in the middle. I was told that I would have to count the 0s in the middle of the string as if it were a 1, as long as there are no more than 2 of them in the middle. 

 

For example:

11110000011    =    4

111001111         =9

111001111000   =9 (would ignore the 0s at the end but count the 0s in the middle as part of the sum)

yabwon
Onyx | Level 15

Hi, try this:

data have;
input x_all :$20. expected ; 
cards;
11110000011 4
111001111 9
111001111000 9 
;
run;

data want;
 set have;
 want = lengthn(prxchange('s/^((1*)0{0,2}(1+))(.*)/$1/', -1, strip(x_all)));
run; 
proc print data=want;
run;

Bart

_______________
Polish SAS Users Group: www.polsug.com and communities.sas.com/polsug

"SAS Packages: the way to share" at SGF2020 Proceedings (the latest version), GitHub Repository, and YouTube Video.
Hands-on-Workshop: "Share your code with SAS Packages"
"My First SAS Package: A How-To" at SGF2021 Proceedings

SAS Ballot Ideas: one: SPF in SAS, two, and three
SAS Documentation



silversta
Calcite | Level 5

Hello @yabwon,

 

This worked beautifully, thank you!

novinosrin
Tourmaline | Level 20

Hi @silversta 

Can you please explain a bit more clearly how you got this result

11110000011    =    4

111001111         =9

111001111000   =9

Would the above mean the following?

11101111         =8

 

 

based upon "Is there a way to modify it to sum through a string of 1 or 2 0s in the middle. I was told that I would have to count the 0s in the middle of the string as if it were a 1, as long as there are no more than 2 of them in the middle. "

novinosrin
Tourmaline | Level 20

Addendum-

@yabwon  has answered your additional requirement even before I could begin

sas-innovate-2024.png

Available on demand!

Missed SAS Innovate Las Vegas? Watch all the action for free! View the keynotes, general sessions and 22 breakouts on demand.

 

Register now!

How to Concatenate Values

Learn how use the CAT functions in SAS to join values from multiple variables into a single value.

Find more tutorials on the SAS Users YouTube channel.

Click image to register for webinarClick image to register for webinar

Classroom Training Available!

Select SAS Training centers are offering in-person courses. View upcoming courses for:

View all other training opportunities.

Discussion stats
  • 22 replies
  • 2616 views
  • 18 likes
  • 7 in conversation