1

How to find groups of n and more 'b' chars and put them into the new list?
Groups - number of n 'b' s which i want to find.

Example:

List<char> charlist = new List<char>() {
  'b', 'a', 'b', 'b', 'b', 'a', 'b', 'b', 'b', 'b'
};

I want to put all 'b' s into the new array which are repeated 3 or more times in a row

Result:

Total 'b' s in a list = 8
Added to the array = 7 (groups of 3 and 4 items combined);

List<char> newCharList = new List<char>() {'b', 'b', 'b', 'b', 'b', 'b', 'b'};
Dmitry Bychenko
  • 180,369
  • 20
  • 160
  • 215
  • So if you had `'b', 'b', 'a', 'c', 'c', 'z', 'b', 'b'` would you want `'b', 'b', 'c', 'c', 'b', 'b'`? – ProgrammingLlama Mar 01 '21 at 07:16
  • No, i want to find only 'b' – Кирилл Досын Mar 01 '21 at 07:17
  • 1
    So you just want `char[] charArray = charlist.Where(c == 'b').ToArray();` then? – ProgrammingLlama Mar 01 '21 at 07:18
  • 3
    @John - No, it appears he wants only the groups of 3 `b`s. The input has 7 `b`s, but the output has 6. – Enigmativity Mar 01 '21 at 07:21
  • 3
    OP: What consitutes a group? Will it always be groups of 3, or are all instances of 2+ `b` characters considered groups? – ProgrammingLlama Mar 01 '21 at 07:22
  • You mean the adjacent `b`s? See the answers [here](https://stackoverflow.com/q/62794857/14171304) for example. Tweak one to return an array instead of the count. – dr.null Mar 01 '21 at 07:37
  • @dr.null - I edited the question to clarify. I want to know how to find all 'b' chars which are grouped/repeated/followed by 3 or more – Кирилл Досын Mar 01 '21 at 07:44
  • 1
    Yes its clear now. Maybe they'd reopen it so someone could post an answer. The referred link should help you though. Just create a `List` to add the adjacent `b`s ONLY. – dr.null Mar 01 '21 at 07:53
  • *I want to know how to find all 'b' chars which are grouped/repeated/followed by 3 or more* - doesn't match your desired output. You have a `b` which is followed by only two `b` but you have included it (it is not followed by 3+ `b`s) – Caius Jard Mar 01 '21 at 07:56
  • 1
    @dr.null yea,this link is simillar to what i want. I hope they reopen the question to post a answer. – Кирилл Досын Mar 01 '21 at 07:58
  • 2
    if it's literally just characters and nothing more complex I would perhaps turn the array of chars into a string and use regex: `var ms = Regex.Matches(new string(array), "b{3,}")` then stick matches together or process their chars in order eg `foreach(char c in string.Join("", ms.Select(m => m.Grous[0].Value))` – Caius Jard Mar 01 '21 at 08:23

3 Answers3

3

Well, a simple foreach loop should do in generalized case; let's implement the routine as enumeration:

  using System.Linq;

  ... 

  private static IEnumerable<T> MyExtraction<T>(IEnumerable<T> source, 
                                                Func<T, bool> selectItem, 
                                                Func<List<T>, bool> selectGroup) {
    List<T> cache = new List<T>();

    foreach (T item in source) {
      if (selectItem(item))
        cache.Add(item);
      else if (cache.Count > 0) { // if we have anything to output 
        if (selectGroup(cache))   // should we output?
          foreach (T result in cache)
            yield return result;   

        cache.Clear();
      }
    } 

    if (cache.Count > 0 && selectGroup(cache))
      foreach (T result in cache)
        yield return result;  
  }

Then we can use it as follow:

  List<char> charlist = new List<char>() { 
    'b', 'a', 'b', 'b', 'b', 'a', 'b', 'b', 'b', 'b' 
  };

  List<char> newCharList = MyExtraction(
     charlist,                   // process charlist
     item => item == 'b',        // extract 'b' 
     group => group.Count >= 3)  // take all groups which size >= 3
  .ToList();                     // materialize as List

  // Let's have a look
  Console.Write(string.Join(", ", newCharList));

Outcome: (7 items - groups of 3 and 4 itemes combined)

  b, b, b, b, b, b, b  
Dmitry Bychenko
  • 180,369
  • 20
  • 160
  • 215
2

Here's a handy extension method:

public static IEnumerable<IEnumerable<T>> GroupByEquals<T>(this IEnumerable<T> source)
{
    var enumerator = source.GetEnumerator();
    var current = default(T);
    var loop = false;
    
    IEnumerable<T> ProduceSame()
    {
        yield return enumerator.Current;
        while (enumerator.MoveNext())
        {
            if (!enumerator.Current.Equals(current))
            {
                loop = true;
                yield break;
            }
            yield return enumerator.Current;
        }
        loop = false;
    }

    while (loop || enumerator.MoveNext())
    {
        current = enumerator.Current;
        yield return ProduceSame().ToArray();
    }
}

This takes the following char list:

List<char> charlist = new List<char>()
{
    'b', 'a', 'b', 'b', 'b', 'a', 'b', 'b', 'b', 'b'
};

And produces:

GroupedByEquals

It's then trivial to turn this into the desired result:

List<char> newCharList =
    charlist
        .GroupByEquals()
        .Where(xs => xs.Count() >= 3 && xs.All(x => x == 'b'))
        .SelectMany(x => x)
        .ToList();
Enigmativity
  • 113,464
  • 11
  • 89
  • 172
0

What about this way:

List<char> charlist = new List<char>() { 'b', 'a', 'b', 'b', 'b', 'a', 'b', 'b', 'b', 'b' };

int repeatCounts = 0;
List<char> result = new List<char>();
foreach (var c in charlist)
{
    if (c == 'b')
    {
        repeatCounts++;
        continue;
    }

    if (repeatCounts >= 3)
    {
        result.AddRange(Enumerable.Repeat('b', repeatCounts));
    }

    repeatCounts = 0;
}

if (repeatCounts >= 3)
{
    result.AddRange(Enumerable.Repeat('b', repeatCounts));
}

foreach (var r in result)
{
    Console.Write(r);
}
Dmitry Stepanov
  • 2,776
  • 8
  • 29
  • 45