3
$\begingroup$

Suppose I have a string like "a-1_b-2_c-3_d-4" with numbers, labels, and separators, and I want to get {a-> 1, b-> 2, c-> 3, d-> 4}, I can do something like:

string1 = "a-1_b-2_c-3_d-4";
vals = ToExpression /@ StringCases[string1, 
{"a-" ~~ a : NumberString -> a, 
"b-" ~~ b : NumberString -> b, 
"c-" ~~ c : NumberString -> c, 
"d-" ~~ d : NumberString -> d}];
result = Thread[{a, b, c, d} -> vals]

{a -> 1, b -> 2, c -> 3, d -> 4}

But sometimes my input has one or more parts missing and I would like the default value to be zero in those cases so that "a-1_d-4" becomes {a -> 1, b -> 0, c -> 0, d -> 4}. I can't think of a way to do this other than search for each value individually and then check to see if the result was empty. Is there a cleaner way to do it?

$\endgroup$
1
$\begingroup$

You could do something like this:

assoc = AssociationThread[{a, b, c, d}, {0, 0, 0, 0}];
string1 = "a-1_d-4";

AssociateTo[
 assoc, 
 AssociationThread @@ 
  Transpose[
   Partition[
    StringCases[StringReplace[string1, "-" -> " "], 
     x : NumberString | "a" | "b" | "c" | "d" :> ToExpression[x]], 
    2]]
 ];
assoc

<|a -> 1, b -> 0, c -> 0, d -> 4|>

You can use Normal on this if you really need a list of rules.

$\endgroup$
  • $\begingroup$ That definitely works for my example, except it treats the - as a negative sign but that is not really an issue. I will mark this as an answer because it does work for the test case. I need to tweak it a bit to get it to work for my more general input but AssociateTo was the key (pun intended) I needed. $\endgroup$ – Rudy Potter Jun 15 '18 at 19:42
  • 1
    $\begingroup$ Ah, I see. Fixed it now. Glad to be of help. $\endgroup$ – Henrik Schumacher Jun 15 '18 at 19:51
0
$\begingroup$

This code works for my actual input which is not as simple as the example data I gave. It is inspired by Schumacher's answer but not nearly as neat.

string2 = "0deg_5kV_60mA_10A_Y1-1.5A";
assoc2 = AssociationThread[{deg, kV, mA, A, X1, Y1, X2, Y2}, {0, 0, 0, 0, 0, 0, 0, 0}];
StringSplit[string2, "_"]
StringCases[#,""|"-"~~x:NumberString|"deg"|"kV"|"mA"|"A"|"X1"|"X2"|"Y1"|"Y2"
  :>ToExpression[x]] & /@ %
%[[;; , ;; 2]] (*Gets rid of the extra A*)
ReverseSort /@ %
AssociateTo[assoc2, AssociationThread @@ Transpose@%] 

{"0deg", "5kV", "60mA", "10A", "Y1-1.5A"}  
{{0, deg}, {5, kV}, {60, mA}, {10, A}, {Y1, 1.5, A}}  
{{0, deg}, {5, kV}, {60, mA}, {10, A}, {Y1, 1.5}}
{{deg, 0}, {kV, 5}, {mA, 60}, {A, 10}, {Y1, 1.5}}
<|deg -> 0, kV -> 5, mA -> 60, A -> 10, X1 -> 0, Y1 -> 1.5, X2 -> 0, Y2 -> 0|>
$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.