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, 2022 at 11:22

0

Your Answer

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

Browse other questions tagged or ask your own question.