2014-02-04 3 views

ответ

3

Seq функция модуль работает и возвращает IEnumerable<_> 'S и DefaultIfEmpty работать и возвращать IEnumerable<_>' с. Как насчет просто обернуть его в функцию, которая является составной.

let inline DefaultIfEmpty d l = System.Linq.Enumerable.DefaultIfEmpty(l, d) 

Это также сохраняет лень.

пример:

Seq.empty |> DefaultIfEmpty 0 

Update

Я сделал библиотеку с открытым исходным кодом встраивание много расширений и статические методы, в том числе Enumerable.defaultIfEmpty - ComposableExtesions

+1

Спасибо за ваш ответ!Я закончил использование этого кода, поскольку он компактный, метод доступен по умолчанию, и я могу использовать его без «открытия пространства имен System.Linq». Кроме того, я верю, что реализация BCL 'DefaultIfEmpty' тестируется против (большинства/всех) возможных сценариев. Использование функции в качестве декоратора выглядит как хорошая техника (и я думаю, что это довольно идиоматично). Еще раз спасибо за ваш ответ. –

+2

Учитывая, что это просто оболочка, я думаю, было бы разумно отметить ее как встроенную. – ildjarn

4

Есть несколько вариантов:

  1. Используйте DefaultIfEmpty, которые могут быть не идиоматическое, но будет работать
  2. написать свой собственный вот так:

    let DefaultIfEmpty (l:'t seq) (d:'t) = 
        match Seq.length l with |0 -> seq [d] |_ -> l 
    
  3. Беспокойства о бесконечных последовательностей

    let DefaultIfEmpty (l:'t seq) (d:'t) = 
        match Seq.isEmpty l with |true -> seq [d] |false -> l 
    
+4

Вы почти наверняка не» t хотите использовать 'Seq.length' для этого - что, если вы получили бесконечную последовательность в качестве входных данных? – kvb

+1

@kvb - исправлено с дополнительным примером –

+0

@John Palmer - Извините. Ваш # 3 дважды оценивает первый элемент. – kaefer

6

Чтобы сохранить ленивость последовательности, мы могли бы работать с состоянием перечислителя.

let DefaultIfEmpty (l:'t seq) (d:'t) = 
    seq{ 
     use en = l.GetEnumerator() 
     if en.MoveNext() then 
      yield en.Current 
      while en.MoveNext() do 
       yield en.Current 
     else 
      yield d } 
+2

Я уверен, что 'use' должен находиться внутри блока' seq {} ', иначе перечислитель будет создан с нетерпением и утилизирован слишком рано. – kvb

+0

@kvb Так много для луча в моем собственном глазу. Исправлена. – kaefer

+2

Спасибо за ваш ответ! Предоставленный код работает. Однако, поскольку Stack Overflow позволяет мне выбрать только один правильный ответ, мне пришлось выбрать тот, который я использовал. Еще раз спасибо за ваш ответ! –

Смежные вопросы