1

I have a string having two different types of data in alternating rows (i.e. two rows make one record). I want to select only those records where length of 2nd (i.e. even row) is less than 1000.

I have tried this but it results in selecting only the eventh row and discards the odd row:

var lessthan1000Length = recordsFile.Where((src, index) => src.Length<1000 && index%2 != 0);

Sample data from recordsFile

2012-12-04 | 10:45 AM | Lahore
Added H2SO4 in the solution. Kept it in the lab temperature for 10 minutes    
2012-12-04 | 10:55 AM | Lahore
Observed the pH of the solution.     
2012-12-04 | 11:20 AM | Lahore
Neutralized the solution to maintain the pH in 6-8 range

Thanks for your guidance.

P.S: Kindly note that the results are required in the form of List<string> as we have to make a new dataset from it.

Failed Scientist
  • 1,977
  • 3
  • 29
  • 48
  • So use `index%2 != 0` instead? It starts with the 0th one, not the 1st one (zero-based index). – Jeppe Stig Nielsen May 15 '16 at 00:08
  • 1
    @JeppeStigNielsen Use `!=` or `==', it doesn't matter as it starts selecting only even, odd rows respectively. I want both rows of the record. Please note that both odd and even row combine to form one record. For example row 353 and row 354 together make one record. I can't select any single row out of them – Failed Scientist May 15 '16 at 00:10
  • The sample data appears to use three rows per record (with each third record a blank line). Is that correct or have you just posted it that way? – Enigmativity May 15 '16 at 00:37
  • @Enigmativity Sorry! Its not 3 rows. I just posted this way. – Failed Scientist May 15 '16 at 00:38
  • Ah, I did not understand immediately that you wanted to "pair up" the entries such that the first two go together, and so on. It reminds me of threads like [Split an `IEnumerable` into fixed-sized chunks (return an `IEnumerable>` where the inner sequences are of fixed length) _duplicate_](http://stackoverflow.com/questions/13709626/). However it could be simpler when we simply want "chunks" of ength 2 (pairs). – Jeppe Stig Nielsen May 15 '16 at 00:44

4 Answers4

5
var odds = recordsFile.Where((str, index) => index % 2 == 0);
var evens = recordsFile.Where((str, index) => index % 2 == 1);

var records = odds.Zip(evens, (odd, even) => new { odd, even })
    .Where(pair => pair.even.Length < 1000);

foreach (var record in records)
    Console.WriteLine(record);
Alexander Petrov
  • 13,457
  • 2
  • 20
  • 49
  • Thanks Alexander so much. There is an issue that I want to select these records and put it into another dataset, so I need them to be in the form of strings (`List` will be best), but its not allowing me to cast the `records' into List. Can you please guide there? – Failed Scientist May 15 '16 at 00:32
  • Should it not be the other way round? Even numbers are 0,2,4, ... I think the modulo must be 0 for evens and not for odds – Flat Eric Mar 23 '19 at 10:27
2
List<string> result = recordFile
  .Select( (str, index) => new {str, index})
  .GroupBy(x => x.index / 2, x => x.str)
  .Where(g => g.Last().Length < 1000)
  .Select(g => g.First() + g.Last())
  .ToList();
Amy B
  • 108,202
  • 21
  • 135
  • 185
1

If you use Microsoft's Reactive Framework team's "Interactive Extensions" you get a nice extension method that can help you.

var query = 
    from pair in lines.Buffer(2)
    where pair[1].Length < 1000
    select pair;

var results = query.ToList();

From your sample data I get this:

results

Just NuGet "Ix-Main" to get the extension methods - there are a lot more there than just .Buffer and many of them are super useful.

Enigmativity
  • 113,464
  • 11
  • 89
  • 172
  • Thanks. That is something new for me. Insha'Allah I will surely look into it. But remember that we need pairs back. Not just even line. Please update it accordingly – Failed Scientist May 15 '16 at 00:55
  • 1
    @TalhaIrfan - I've updated the answer to pull back the pairs. It is even simpler now. – Enigmativity May 15 '16 at 02:07
1

Alexander's answer seems to work fine.

Alternatively, you can create a method to turn a sequence (with an even number of terms) into a sequence of pairs. I guess something like:

static IEnumerable<Tuple<T, T>> PairUp<T>(this IEnumerable<T> src)
{
  using (var e = src.GetEnumerator)
  {
    while (e.MoveNext())
    {
      var first = e.Current;

      if (!e.MoveNext())
        throw new InvalidOperationException("Count of source must be even"); // OR: yield break; OR yield return Tuple.Create(first, default(T)); yield break;
      var second = e.Current;

      yield return Tuple.Create(first, second);
    }
  }
}

With that you could do recordsFile.PairUp().Where(t => t.Item2.Length < 1000) or similar.

Edit: Since you want the two "parts" concatenated as strings, that would be recordsFile.PairUp().Where(t => t.Item2.Length < 1000).Select(t => t.Item1 + t.Item2).

Jeppe Stig Nielsen
  • 60,409
  • 11
  • 110
  • 181