3
$\begingroup$

I have a very large network with 1000's of edges. Below is a small sample. The N is my label for Node and the number that follows is a unique identifier. I want to make all the edges on either side of the arrow (->) into a string of 6 characters. If the left side of the arrow has just 5 characters, then I want to all insert a 0 to the right of the N. Likewise, if the right side of the arrow has just 5 characters, then I want to all insert a 0 to the right of the N. If both sides of the arrow already have 6 characters then do nothing to that edge. The set edges2 is the outcome I'm trying to reach from starting with edges1. Any assistance is much appreciated!

edges1 = {N1003 -> N1003, N1003 -> N1099, N1003 -> N12059, 
  N1003 -> N22007, N1003 -> N1025}
edges2 = {N01003 -> N01003, N01003 -> N01099, N01003 -> N12059, 
  N01003 -> N22007, N01003 -> N01025}
$\endgroup$
5
  • $\begingroup$ edges1 /. x_Symbol /; StringTake[tmp = ToString[x], 1] == "N" && StringLength[tmp] == 5 :> "N0" <> StringTake[tmp, {2, 5}] $\endgroup$ Commented Aug 4 at 7:27
  • $\begingroup$ {N01025->N01025,N01025->N01025,N01025->N12059,N01025->N22007,N01025->N01025} $\endgroup$
    – user42700
    Commented Aug 4 at 12:11
  • $\begingroup$ hmmm...seems to not produce edges2 but some other edge set using N01025 in all the pairs. $\endgroup$
    – user42700
    Commented Aug 4 at 12:13
  • $\begingroup$ Sorry, should read: edges1 /. x_Symbol /; (StringTake[ToString[x], 1] == "N" && StringLength[ToString[x]] == 5) :> "N0" <> StringTake[ToString[x], {2, 5}] $\endgroup$ Commented Aug 4 at 18:08
  • $\begingroup$ nice!!!!!!!!!!!!!!!!!!!! $\endgroup$
    – user42700
    Commented Aug 4 at 18:16

3 Answers 3

3
$\begingroup$
((edges1 /. Rule[a_,b_] :> Rule[ToString[a],ToString[b]]) /. 
(str_String /; StringLength[str]==5) :>
    StringJoin@Insert[StringTakeDrop[str,1],"0",2])/.
    str_String :> Symbol[str]

(* {N01003->N01003,N01003->N01099,N01003->N12059,N01003->N22007,N01003->N01025} *) 

% === edges2

(* True *) 
$\endgroup$
1
  • $\begingroup$ A. Kato: This is a neat solution and very clever ... many thanks for all your help ... regards ... 42700 $\endgroup$
    – user42700
    Commented Aug 4 at 4:34
3
$\begingroup$

You say "string" but all of your N1003-like things are symbols. So, I'll cover both cases. We start with a helper method that works on a single string/symbol

StringPadAt2[s_String] := StringInsert[s, "0", 2] /; 5 == StringLength[s];
StringPadAt2[s_Symbol] := Symbol[StringInsert[SymbolName[s], "0", 2]] /; 5 == StringLength[SymbolName[s]];
StringPadAt2[s_] := s

So, if we have strings and we want strings:

edges1Strings = {"N1003" -> "N1003", "N1003" -> "N1099", "N1003" -> "N12059", "N1003" -> "N22007", "N1003" -> "N1025"};
Map[StringPadAt2, edges1Strings, {-1}]
(* {"N01003" -> "N01003", "N01003" -> "N01099", "N01003" -> "N12059", "N01003" -> "N22007", "N01003" -> "N01025"} *)

Alternately, you could use ReplaceAll:

edges1Strings /. {s_String :> StringPadAt2[s]}

If we have symbols and we want symbols:

edges1Symbols = {N1003 -> N1003, N1003 -> N1099, N1003 -> N12059, N1003 -> N22007, N1003 -> N1025};
Map[StringPadAt2, edges1Symbols, {-1}]
(* {N01003 -> N01003, N01003 -> N01099, N01003 -> N12059, N01003 -> N22007, N01003 -> N01025} *)

And again with ReplaceAll:

edges1Symbols /. {s_Symbol :> StringPadAt2[s]}

This can be adjusted to do string->symbol or symbol->string. As it stands, I'm assuming that we always start with strings/symbols that are 5 or 6 characters long. If you have other cases, this would need to be generalized.

$\endgroup$
1
  • $\begingroup$ lericr: thank you for that clarification on symbol vs string; wonderful code and thank u for sharing this! $\endgroup$
    – user42700
    Commented Aug 4 at 4:31
2
$\begingroup$
edges1 = {N1003 -> N1003, N1003 -> N1099, N1003 -> N12059, 
          N1003 -> N22007, N1003 -> N1025};

edges2 = {N01003 -> N01003, N01003 -> N01099, N01003 -> N12059, 
          N01003 -> N22007, N01003 -> N01025};

Using StringReplace:

f[str_String] /; StringLength@ToString@str != 5 := str

f[str_String] /; StringLength@ToString@str == 5 := 
StringReplace[str, # -> # <> "0"] &@StringTake[str, 1]

(edges1 /. 
Rule[a_, b_] :> Map[Symbol@*f]@(Rule @@ (ToString /@ {a, b}))) === edges2

True

Or using StringReplacePart:

f[s_Symbol] := 
With[{ss = ToString@s}, 
If[StringLength@ss == 5, 
Symbol[StringReplacePart[#, StringTake[#, 1] <> "0", {1, 1}] &@ss], s]]

Map[f, edges1, {-1}] === edges2

True

$\endgroup$
1
  • $\begingroup$ clever with StringReplace ... nice idea!! ... thank u! $\endgroup$
    – user42700
    Commented Aug 5 at 10:47

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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