Hershul
Hershul

Reputation: 31

Analyze repeating sequences

Suppose I have an array of integers containing the following: [1,2,2,3,1,5,4,4,1,1,1]

How would I write a script that would divide the array into sub-arrays based on repeated neighbors ?

For example: [1],[2,2],[3],[1],[5],[4,4],[1,1,1]

Yet even better would be to receive an array of tuples denoting the value, position of first occurrence,& number of times repeated, for example: [ (1, 0, 1), (2, 1, 2), (3, 3, 1), (1, 4, 1) (5, 5, 1), (4, 6, 2), (1, 8, 3) ]

Here is what I tried writing originally but it doesn't seem to work right:

        var array = handStacks;
        var analysis = new List<(int, int, int)>();
        var subArrayStart = 0;
        var subArraySize = 0;
        for(var x=0; x < array.Length; x++){
            var curr = array[x];

            // Last element
            if(x == array.Length - 1){
                if(subArrayStart == 0) subArraySize++;

                analysis.Add( (subArraySize, array[subArrayStart], subArrayStart) );

            }  
            else if(curr != array[subArrayStart]) { // New sub array

                analysis.Add( (subArraySize, array[subArrayStart], subArrayStart) );

                subArraySize = 1;
                subArrayStart = x;
            }

            subArraySize++;
        }

Upvotes: 2

Views: 167

Answers (4)

Pavel Anikhouski
Pavel Anikhouski

Reputation: 23258

This code will give you the expected list of (int, int, int) tuple. At every loop iteration you are creating a tuple instance and increment the element occurrence (until it's the same)

var array = new[] { 1, 2, 2, 3, 1, 5, 4, 4, 1, 1, 1 };
var analysis = new List<(int, int, int)>();

for (int i = 0; i < array.Length; i++)
{
    var item = (value: array[i], position: i, occurence: 1);
    var index = i + 1;
    while (index < array.Length && array[index++] == item.value)
    {
        item.occurence++;
        i++;
    }
    analysis.Add(item);
}

Console.WriteLine(string.Join(", ", analysis));

And it'll print

(1, 0, 1), (2, 1, 2), (3, 3, 1), (1, 4, 1), (5, 5, 1), (4, 6, 2), (1, 8, 3)

Upvotes: 1

MarcG
MarcG

Reputation: 342

For your "even better solution" I would suggest:

    int[] arr = { 1, 2, 2, 3, 1, 5, 4, 4, 1, 1, 1 };
 var  targetsList = new List<(int,int,int)>();
 int currentValue = arr[0];
 int position = 0;
 int repeats =0;
 for (int i = 0; i < arr.Length; i++)
{
    if (arr[i]!=currentValue)
    {
        targetsList.Add((currentValue,position,repeats));
        position = i;
        currentValue = arr[i];
        repeats = 0;
    }
    repeats++;
}
targetsList.Add((currentValue,position,repeats));
foreach(var target in targetsList)
{
    Console.WriteLine($"Value {target.Item1},Position {target.Item2},Repeats {target.Item3}");
}

Upvotes: 2

Sweeper
Sweeper

Reputation: 272895

Here is a more generic solution, using yield return:

public static IEnumerable<(T, int, int)> Group<T>(IEnumerable<T> source) where T: IEquatable<T> {
    if (!source.Any()) { // if input is empty, return empty sequence
        yield break;
    }
    // element of current sub array
    T currentElement = source.First();
    int startIndex = 0; // ...of current sub array
    int currentIndex = 0; // ...of the input sequence
    int count = 0; // ...of current sub array
    foreach(T elem in source) {
        if (elem.Equals(currentElement)) {
            count++;
        } else {
            // when we find a different element, return everything we know about the current sub array
            yield return (currentElement, startIndex, count);
            // reset info about the current sub array
            currentElement = elem;
            startIndex = currentIndex;
            count = 1;
        }
        currentIndex++;
    }
    // after we iterated the whole input sequence, we return another sub array
    yield return (currentElement, startIndex, count);
}

Usage:

List<(int, int, int)> result = Group(yourInputArray).ToList();

Upvotes: 1

fubo
fubo

Reputation: 45977

Approach with a simple for loop

public static int[][] GroupBySequences(int[] items)
{
    List<List<int>> result = new List<List<int>>();
    List<int> currentArray = new List<int> { items[0] };
    for (int i = 1; i < items.Length; i++)
    {
        if (items[i] != items[i - 1])
        {
            result.Add(currentArray);
            currentArray = new List<int>();
        }
        currentArray.Add(items[i]);
    }
    result.Add(currentArray);
    return result.Select(x => x.ToArray()).ToArray();
}

Upvotes: 1

Related Questions