1

I have a list of following characters of class Token:

3 ( 16 ) 23 ( 24 ( 40 ) 50 ( 66 ) 76 ) 83 ( 88 ( 104 ) 127 )

My requirement is to find the pair of parenthesis within this list. In the list, the pairs of parenthesis are: 3,16; 24,40; 50,66; 23,76; 88,104; 83,127.

I'm trying to do this with following approach:

public static Dictionary<int,int> GetPair(List<Token> data)
{
     List<Token> token = data;
     var pair = new Dictionary<int, int>();

     int startIndex = -1;
     int currentPosition = -1;
     int finalIndex = -1;

     foreach (var item in token)
     {
         if (item.TokenValue == "(" && (currentPosition == -1 || currentPosition>startIndex) )
         {
             startIndex = item.TokenID;
             currentPosition = startIndex;
         }
         if (item.TokenValue == ")")
         {
             finalIndex = item.TokenID;
             currentPosition = finalIndex;
             pair.Add(startIndex, finalIndex);
         }               
     }   

     return pair;
}

public class Token
{
    public int TokenID { get; set; }
    public string TokenValue { get; set; }
}

I'm stuck in finding the position of "23 (" because there is another opening parenthesis in the list and it replaces it with "24 (". Kindly help me to fix the logic here??

Yael
  • 1,566
  • 3
  • 18
  • 25
Sahil Sharma
  • 1,813
  • 1
  • 16
  • 37

4 Answers4

3

I've not tested it but this should solve the problem:

public static Dictionary<int,int> GetPair(List<Token> data)
{
    var pair = new Dictionary<int, int>();

    var stack = new Stack<Token>();
    foreach (var item in token)
    {
        if (item.TokenValue == "(")
        {
            stack.Push(item);
            continue;
        }

        if (item.TokenValue == ")")
        {
            var starting = stack.Pop();
            pair.Add(starting.TokenId, item.TokenId);
        }
    }

    return pair;
}
Sebastian Schumann
  • 3,204
  • 19
  • 37
1

This is a classic interview qustion, you solve it with a Stack:

public static Dictionary<int,int> GetPair(List<Token> data)
{
    Stack<Token> stacken = new Stack<Token>();
    var pair = new Dictionary<int, int>();
    Token temp = new Token();

    foreach (char A in data)
    {
         if (item.TokenValue == "(" )
         {
              stacken.Push(A);
         }

         if (item.TokenValue == ")" )
         {
             if (stacken.Last() == '(')
             {
                  temp = stacken.Pop();
                  pair.Add(temp.TokenID,item.TokenID)
             }
             else
             {
                  stacken.Push(A);
             }
         }
    }

    return pair; 
}         
Yael
  • 1,566
  • 3
  • 18
  • 25
0

You can also use regex. Probably it's not too fast like Vera rind solution.

string s = "3 ( 16 ) 23 ( 24 ( 40 ) 50 ( 66 ) 76 ) 83 ( 88 ( 104 ) 127 )".Replace(" ", string.Empty);
Regex regex = new Regex(@"(([0-9]+)\([0-9]+\))");
Regex regexNumber = new Regex(@"[0-9]+");
Match match = regex.Match(s);
List<Tuple<int, int>> pairs = new List<Tuple<int, int>>();
while (match.Success)
{
     var pairNumber = regexNumber.Matches(match.Value);
     if (pairNumber.Count == 2)
     {
         var newPair = new Tuple<int, int>(int.Parse(pairNumber[0].Value), int.Parse(pairNumber[1].Value));
         pairs.Add(newPair);
     }

     // remove last parse
     s = s.Replace(match.Value, string.Empty);
     match = regex.Match(s);
 }
Jiri Sykora
  • 484
  • 4
  • 10
0

EDIT

Thanks to Vera rind suggestion, I wrote also solution to do that for every (nested level) with NET regex flavour, with regular expression:

(?<first>\d+)(?=\s\(\s(?<second>\d+)\s\))|(?<first>\d+)\s(?=\(\s(?:(?:[^()]|(?<Open>\()|(?<Content-Open>\)))+(?(Open)(?!))\s(?<second>\d+)))

DEMO

it captures pairs of values in groups first and second. Regex directly match first value of pairs, the second one is captured by group in positive lookahead. It is not the most efficient way, just easier to verified in regex tester if it match properly.

OLD ANSWER

In other regex flavours (as far I know) there is no such elegant way to match balanced repatable structures, so for two level of brackets, this solution still works. The stact solution is better in this case, but if whole data is in same format (spacing and max two level paratheses depth) it is also possible with regex:

(\d+)\s\(\s(\d+)\s\)|(\d+)(?=\s\(\s(?:\d+\s\(\s\d+\s\)\s)+(\d+))

DEMO

Where:

  • (\d+)\s\(\s(\d+)\s\) - match simple case: namber with following number in brackets: n1 (n2) , values are captured in groups 1 & 2,
  • (\d+)(?=\s\(\s(?:\d+\s\(\s\d+\s\)\s)+(\d+)) - match number with last lonely number in following nested brackets: n1 ( x1 (x2) y1 (y2) n2 ), values are captured in groups 3 & 4,

However it will chage list order.

m.cekiera
  • 5,365
  • 5
  • 21
  • 35
  • 1
    You can use regex for any depth: `([^()]|(?[(])|(?[)]))+(?(open)(?!))` A good explanation is [here](http://stackoverflow.com/a/17004406/2729609) and [here](http://stackoverflow.com/a/13425789/2729609). The problem is that the source data it not a string. – Sebastian Schumann Sep 15 '15 at 12:15
  • @Verarind but when I try you regex with RegexHero or or RegexStorm, is returns wrong result. And how it should deal with matching `n1 ( x1 (x2) y1 (y2) n2 )` pattern? – m.cekiera Sep 15 '15 at 12:35
  • 1
    @mcekiera My regex is only a hint not the solution. It uses [balancing group definitions](https://msdn.microsoft.com/en-us/library/bs2twtah(v=vs.110).aspx) to match the corresponding parenthesis. This could be used to find the matching pairs. The specified regex doesn't recognize any numbers between the parenthesis - or better the relation between number and parenthesis is lost. The hint is for you in case that you need something like that. – Sebastian Schumann Sep 15 '15 at 12:40
  • @Verarind Ok, I understand, this is really interesting and unique NET regex flavour capability. Thank you for comment, sorry for misunderstanding – m.cekiera Sep 15 '15 at 12:44
  • 1
    @Verarind I learned how it works and modified my answer, thank you very much once again for hint, it is really valuable lesson for me – m.cekiera Sep 15 '15 at 13:19