Как обнаружить строки, которые являются уникальными в большом файле, используя Reactive Extensions - PullRequest
0 голосов
/ 22 ноября 2018

Мне нужно обработать большие файлы CSV (до десятков ГБ), которые выглядят так:

Key,CompletedA,CompletedB
1,true,NULL
2,true,NULL
3,false,NULL
1,NULL,true
2,NULL,true  

У меня есть парсер, который выдает проанализированные строки как IEnumerable<Record>, так что я только для чтенияпо одной строке за раз в памяти.

Теперь мне нужно сгруппировать записи по ключу и проверить, имеют ли столбцы CompletedA и CompletedB значение в группе.На выходе мне нужны записи, в которых нет ни CompletedA, ни CompletedB внутри группы.

В этом случае это запись с ключом 3.

Однако, происходит много подобных обработокодин и тот же набор данных, и я не хочу повторять его несколько раз.

Я думаю, что могу преобразовать IEnumerable в IObservable и использовать Reactive Extentions для поиска записей.

Можно ли это сделатьэто эффективный для памяти способ с простым выражением Linq над коллекцией IObservable?

Ответы [ 2 ]

0 голосов
/ 22 ноября 2018

Я думаю, что это будет делать то, что вам нужно:

var result =
    source
        .GroupBy(x => x.Key)
        .SelectMany(xs =>
            (xs.Select(x => x.CompletedA).Any(x => x != null && x == true) && xs.Select(x => x.CompletedA).Any(x => x != null && x == true))
            ? new List<Record>()
            : xs.ToList());

Использование Rx здесь не поможет.

0 голосов
/ 22 ноября 2018

При условии, что Key является целым числом, мы можем попробовать использовать Dictionary и одно сканирование:

 // value: 0b00 - neither A nor B
 //        0b01 - A only
 //        0b10 - B only
 //        0b11 - Both A and B    
 Dictionary<int, byte> Status = new Dictionary<int, byte>();

 var query = File
   .ReadLines(@"c:\MyFile.csv")
   .Where(line => !string.IsNullOrWhiteSpace(line))
   .Skip(1) // skip header 
   .Select(line => YourParserHere(line));

 foreach (var record in query) {
   int mask = (record.CompletedA != null ? 1 : 0) |
              (record.CompletedB != null ? 2 : 0); 

   if (Status.TryGetValue(record.Key, out var value))
     Status[record.Key] = (byte) (value | mask);
   else
     Status.Add(record.Key, (byte) mask);
 }

 // All keys that don't have 3 == 0b11 value (both A and B)  
 var bothAandB = Status
   .Where(pair => pair.Value != 3)
   .Select(pair => pair.Key); 
...