1
\$\begingroup\$

There is a String.Replace method in C# and it is 1-1 mapping replacing operation, i.e. single Unicode character / string source replaced with another single Unicode character / string target. Considering the case of 1-to-multiple replacing task, for example, replacing "1" in "123" with "A", "B" and "C" separately (result: "A23", "B23" and "C23"), I am attempting to propose a Generate method to deal with this kind of task.

Replacing Rule Representation

Tree structure is used for representing 1-to-multiple replacing rule. Following the mentioned example, the tree structure is like:

(root)-- "1" ---- "A"
            |---- "B"
            |---- "C"

The nodes in level 2 are the old strings to be replaced and the the nodes in level 3 are the new strings to replace all occurrences of its parent node.

The experimental implementation

  • Generate method implementation:

    public static class StringsBatchReplacingTool
    {
      public static List<string> Generate(string inputString, NTree<string> replacingRules)
      {
        List<string> results = new List<string>();
        results.Add(inputString);
        foreach (var Node in replacingRules.Nodes)      //    First layer
        {
          if (!inputString.Contains(Node.Data))
          {
            continue;
          }
          results = BatchReplace(results, Node);
        }
        return results;
      }
    
      private static List<string> BatchReplace(List<string> input, NTree<string> replacingRules)
      {
        List<string> results = new List<string>();
        foreach (var replaceTarget in replacingRules.Nodes)
        {
          foreach (var inputItem in input)
          {
            results.Add(inputItem.Replace(replacingRules.Data, replaceTarget.Data));
          }
        }
        return results;
      }
    }
    
  • The used NTree class implementation:

    //  Reference: https://stackoverflow.com/a/2012855
    
    public delegate void TreeVisitor<T>(T nodeData);
    
    public class NTree<T>
    {
      public T Data;
      public LinkedList<NTree<T>> Nodes;
    
      public NTree()
      {
        Nodes = new LinkedList<NTree<T>>();
      }
    
      public NTree(T data)
      {
        this.Data = data;
        Nodes = new LinkedList<NTree<T>>();
      }
    
      public void AddChild(T data)
      {
        Nodes.AddFirst(new NTree<T>(data));
      }
    
      public void AddChild(IEnumerable<T> data)
      {
          foreach (var eachData in data)
          {
            AddChild(eachData);
          }
      }
    
      /// <summary>
      /// Get the specific child with the given index.
      /// </summary>
      /// <param name="i">Index of child, start from 0</param>
      /// <returns></returns>
      public NTree<T> GetChild(int i)
      {
        i++;
        foreach (NTree<T> n in Nodes)
          if (--i == 0)
            return n;
        return null;
      }
    
      public void Traverse(NTree<T> node, TreeVisitor<T> visitor)
      {
        visitor(node.Data);
        foreach (NTree<T> kid in node.Nodes)
          Traverse(kid, visitor);
      }
    

Test Cases

Following the mentioned example, the code for testing:

NTree<string> nTree = new NTree<string>();
nTree.AddChild("1");
nTree.GetChild(0).AddChild("C");
nTree.GetChild(0).AddChild("B");
nTree.GetChild(0).AddChild("A");

var testResults = StringsBatchReplacingTool.Generate("123", nTree);
foreach (var eachResult in testResults)
{
    Console.WriteLine(eachResult);
}

The output of above code:

A23
B23
C23

Another more complex test case: for input string "123", replacing "1" with "A", "B" and "C" and replacing "2" with "D", "E" and "F" separately.

NTree<string> nTree = new NTree<string>();
nTree.AddChild("1");
nTree.GetChild(0).AddChild("C");
nTree.GetChild(0).AddChild("B");
nTree.GetChild(0).AddChild("A");
nTree.AddChild("2");
nTree.GetChild(0).AddChild("F");
nTree.GetChild(0).AddChild("E");
nTree.GetChild(0).AddChild("D");

var testResults = StringsBatchReplacingTool.Generate("123", nTree);
foreach (var eachResult in testResults)
{
    Console.WriteLine(eachResult);
}

The output of above code:

AD3
AE3
AF3
BD3
BE3
BF3
CD3
CE3
CF3

All suggestions are welcome.

\$\endgroup\$
1
  • 1
    \$\begingroup\$ This triple foreach inside the Generate method seems really suspicious. Are you sure you need all of them? As I can see you have a recursive Traverse method which is unused. Do you use it in a different code piece which is not shared with us? \$\endgroup\$ Apr 4 at 11:22

0

Your Answer

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

Browse other questions tagged or ask your own question.