Search code examples
c#algorithmdetection

Detect transitions in a list of objects


I have an ordered list of objects (named LO).
Each object (named Ob) is a list of one or more int? elements (List <int?>), such as: <30> or <30, null> or <null> or <28, 30>, etc. Edit: In this list each element is unique.

I need to detect (and count) transitions in the list of objects, a transition being a certain sequence in the order of objects in the LO list. (Edit: I use -> to indicate the next object. Ex. <A> -> <B> are 2 objects in the list of objects LO: say the 3rd is <A> and the 4th is <B>:

<A> -> <B> :transition
<A> -> <null> -> <B> or  <A> -> <null> ->...-> <null> -> <B> : transition
<A> -> <A,B> -> <B or  <A> -> <A,B> ->...-> <A,B> ->B :transition
<A> -> <null> -> <A> : transition

The <A> -> <AB> -> <A> is the exception, it is not a transition, and of course any combination of repeating <A>-><A>, <null> -> <null>, <A,B> -> <A,B>, etc. is not a transition.

Edit: Transitions only sequences that start with single objects (like ) and end with single objects (like ). -> -> is not a sequence of elements that identify a transition.

How can I do that? My idea would be to detect the A -> (*)A -> A pattern as the exception. Should I pre-filter the list to exclude repeating data?


Solution

  • Ok, I created a program (also available on dotnetfiddle.com) with which I tried to fulfill your requirements. But I still think your specifications are unclear.

    This is what I've implemented:

    • A list of objects (LO) can contain objects (OB).
    • An (OB) is a list of String (must be replaced with int? in your scenario).
    • An OB is treated as a Set. Duplicates are allowed but ignored.
    • OBs are the same when they contain the same Strings.
    • When the LO is empty, transitions is 0
    • When the LO contains only one OB, transitions is 0
    • When the first OB or the last OB in the LO have more than one String, transitions is 0
    • The number of transitions is increased by one when two subsequent OBs are not the same.

    I added a few remarks in the output because I don't understand what you mean.

    Output

    [A] -> [B] : 1
    
    [A] -> [null] -> [B] : 2
    
    [A] -> [null] -> [null] -> [null] -> [null] -> [B] : 2
    
    [A] -> [A,B] -> [B] : 2
    
    [A] -> [null] -> [A] : 2
    
    [A] -> [A,B] -> [A] : 2
    Why is this not a transition but an exception?
    
    [A] -> [A,null] -> [A,null,null] -> [A] : 2
    [A,null] and [A,null,null] are considered equal as per your second comment.
    
    [A] -> [A,B,null,C] -> [A] : 2
    As per your first comment.
    
    [A] -> [A,B] -> [B,A] -> [A] : 2
    Second and third OB are equal as per your first comment.
    
    [A] -> [null,A] -> [B] : 2
    
    [A] -> [A,B,C] -> [B] : 2
    Why is this not a transition as per your fourth comment?
    

    Source code

    using System;
    using System.Collections.Generic;
    using System.Linq;
    
    public class Program
    {
        public static string A = "A";
        public static string B = "B";
        public static string C = "C";
        public static string NULL = "null";
    
        public static void Main()
        {   
            var lo = new LO();
            lo.Add(new OB{A});
            lo.Add(new OB{B});
            lo.DisplayResult();
    
            lo.Clear();
            lo.Add(new OB{A});
            lo.Add(new OB{NULL});
            lo.Add(new OB{B});
            lo.DisplayResult();
    
            lo.Clear();
            lo.Add(new OB{A});
            lo.Add(new OB{NULL});
            lo.Add(new OB{NULL});
            lo.Add(new OB{NULL});
            lo.Add(new OB{NULL});
            lo.Add(new OB{B});
            lo.DisplayResult();
    
            lo.Clear();
            lo.Add(new OB{A});
            lo.Add(new OB{A,B});
            lo.Add(new OB{B});
            lo.DisplayResult();
    
            lo.Clear();
            lo.Add(new OB{A});
            lo.Add(new OB{NULL});
            lo.Add(new OB{A});
            lo.DisplayResult();
    
            lo.Clear();
            lo.Add(new OB{A});
            lo.Add(new OB{A,B});
            lo.Add(new OB{A});
            lo.DisplayResult("Why is this not a transition but an exception?");
    
    
            lo.Clear();
            lo.Add(new OB{A});
            lo.Add(new OB{A,NULL});
            lo.Add(new OB{A,NULL,NULL});
            lo.Add(new OB{A});
            lo.DisplayResult("<A,NULL> and <A,NULL,NULL> are considered equal as per your second comment.");
    
            lo.Clear();
            lo.Add(new OB{A});
            lo.Add(new OB{A,B,NULL,C});
            lo.Add(new OB{A});
            lo.DisplayResult("As per your first comment");
    
            lo.Clear();
            lo.Add(new OB{A});
            lo.Add(new OB{A,B});
            lo.Add(new OB{B,A});
            lo.Add(new OB{A});
            lo.DisplayResult("Second and third OB are equal as per your first comment");
    
            lo.Clear();
            lo.Add(new OB{A});
            lo.Add(new OB{NULL,A});
            lo.Add(new OB{B});
            lo.DisplayResult();
    
            lo.Clear();
            lo.Add(new OB{A});
            lo.Add(new OB{A,B,C});
            lo.Add(new OB{B});
            lo.DisplayResult("Why is this not a transition as per your fourth comment?");
        }
    }
    
    // list of objects (LO) = list<OB>
    public class LO : List<OB>
    {
        public void DisplayResult(string message = null)
        {
            Console.WriteLine("{0} : {1}",this,CountTransitions());
            if(message != null)
            {
                Console.WriteLine(message);
            }
            Console.WriteLine();
        }
    
        private int CountTransitions()
        {
            if(this.Any()== false || this.Count == 1) return 0;
    
            var first = this.FirstOrDefault();
            var last = this.LastOrDefault();
    
            // first OB and last OB must have exactly one element.
            if(first.Count != 1 || last.Count != 1) return 0;
    
            var transitions = 0;
            for(var i = 0; i < this.Count - 1; i++)
            {
                // when current OB and next OB are not the same, it is a transition
                transitions = IsTransition(this[i],this[i+1]) ? transitions + 1 : transitions;
            }
            return transitions;
        }
    
        private bool IsTransition(OB lhs, OB rhs)
        {
            var lhsSet = new SortedSet<String>(lhs);
            var rhsSet = new SortedSet<String>(rhs);
            return lhsSet.SetEquals(rhsSet) == false;
        }
    
        public override string ToString()
        {
            return String.Join(" -> ", this.Select(x => x.ToString()));
        }
    }
    
    // objects (OB) = list<int?>
    public class OB : List<String>
    {
        public override String ToString()
        {
            return String.Format("[{0}]", String.Join(",", this));
        }
    }