Как инициализировать список F#, когда размер неизвестен, используя цикл while..do

У меня есть функция, которая будет анализировать результаты DataReader, и я не знаю, сколько элементов возвращается, поэтому я хочу использовать цикл while..do для итерации по считывателю, и результатом должен быть список определенного типа. .

(fun(reader) ->
            [
                while reader.Read() do
                    new CityType(Id=(reader.GetInt32 0), Name=(reader.GetString 1), StateName=(reader.GetString 2))
            ])

Это то, что я пытался, но предупреждение, которое я получаю:

This expression should have type 'unit', but has type 'CityType'. Use 'ignore' to discard the result of the expression, or 'let' 
to bind the result to a name.

Итак, как лучше всего перебрать DataReader и создать список?


person James Black    schedule 24.05.2010    source источник
comment
Я пытался выяснить то же самое. Рад, что вы спросили. +1   -  person    schedule 07.02.2017


Ответы (2)


вы можете использовать понимание списка:

[
   while reader.Read() do
       let d =  new CityType(Id=(reader.GetInt32 0), Name=(reader.GetString 1), StateName=(reader.GetString 2))
       yield d
]

Вот еще один пример:

/// The squares of the first 10 integers
let squaresOfOneToTen = [ for x in 0..10 -> x*x ]

or

let squaresOfOneToTen = [ for x in 0..10 do yield x*x ]

Вы также можете сделать это для последовательностей и массивов:

seq { 
   for i=1 to 9 do 
      for j=1 to 9 do
         yield (i,j,i*j)
}


[| for i=1 to 100 do yield i*i |]

вы также можете получить подпоследовательность в последовательности (yield!), вот пример использования Project Euler 31< /а>.

person Yin Zhu    schedule 24.05.2010
comment
Спасибо за помощь. Я забыл о ключевом слове yield. - person James Black; 24.05.2010

Просто чтобы предоставить некоторую дополнительную информацию, которая может объяснить, что здесь происходит - есть два способа создания списков в F#, и в обоих случаях вы пишете что-то в квадратных скобках [ ... ] (что может быть немного запутанно поначалу!)

Литералы списков используются, когда у вас есть несколько выражений (известное количество явно написанных выражений) и вы хотите создать список, содержащий результаты оценки этих выражений. Например:

[ 1; 2; 3; ]       // list of constant expressions
[ 1+1; 2+2; 3+3 ]  // creates list [ 2; 4; 6 ]

Списковые включения используются, когда у вас есть код, который что-то делает и генерирует список элементов (путем создания элементов во время вычисления). Это то, что Инь Чжу использует в своем ответе. Некоторые примеры:

[ yield 1; ]           // generates singleton list [ 1 ] 
[ yield 1; yield 2; ]  // generates list with two elements
[ for x in 1 .. 10 do  // iterates loop 10 times
    yield x * x ]      // ... generates element during every iteration

Расширенные функции
Вы также можете использовать yield! для одновременного создания нескольких элементов:

[ yield! [ 1; 2 ]      // generates a list containing [ 1; 2; 3; 4 ]
  yield! [ 3; 4 ] ]

Это можно использовать для написания рекурсивных функций, поэтому вы можете переписать свой код, используя рекурсию вместо цикла (это было бы полезно, если бы вам нужно было сохранить какое-то состояние, но, как сейчас выглядит ваш код, while прекрасно!)

let rec loop reader = 
  [ if reader.Read() then
      yield new CityType(Id=(reader.GetInt32 0), Name=(reader.GetString 1), 
                         StateName=(reader.GetString 2))   
      yield! loop reader ]

Это шаблон, который часто появляется в списках, так что знать о нем полезно :-).

person Tomas Petricek    schedule 24.05.2010
comment
Большое спасибо за дополнительную информацию. Последний раздел, я ожидаю, скоро будет очень полезен. - person James Black; 24.05.2010
comment
От настоящего эксперта F#! В последнее время читаю много ваших статей. Спасибо :) - person ; 07.02.2017