开发者

How to initialize F# list when size is unknown, using while..do loop

I have a function that will parse the results of a DataReader, and I don't know how many items are returned, so I want to use a while..do loop to itera开发者_运维技巧te over the reader, and the outcome should be a list of a certain type.

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

This is what I tried, but the warning I get is:

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.

So what is the best way to iterate over a DataReader and create a list?


you can use list comprehension:

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

Here is one more example:

/// 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 ]

You can also do it for sequences and arrays:

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 |]

you can also yield a sub sequence in a sequence(yield!), here is an example using Project Euler 31.


Just to provide some additional information that may explain what is going on here - there are two ways of creating lists in F# and in both cases, you're writing something in square braces [ ... ] (which may be a bit confusing at first!)

List literals are used when you have a few expressions (known number of explicitly written expressions) and want to create a list containing the results of evaluating these expressions. For example:

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

List comprehensions are used when you have some code that does something and generates list of elements (by producing elements during the calculation). This is what Yin Zhu uses in his answer. Some examples are:

[ 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

Advanced features
You can also use yield! to generate multiple elements at once:

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

This can be used for writing recursive functions, so you could rewrite your code using recursion instead of loop (this would be useful if you needed to keep some state, but as your code looks currently, while is perfectly fine!)

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 ]

This is a pattern that often appears in list comprehensions, so it is useful to know about it :-).

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜