2

How can I increment counter while inside a LINQ query?

Consider the following

Public Class SimpleString
    Public Property Value As String
End Class

...

Public Shared Sub SetStuff()

    Dim stringList As IEnumerable(Of SimpleString) =
        {New SimpleString With {.Value = "0"},
         New SimpleString With {.Value = "0"},
         New SimpleString With {.Value = "0"},
         New SimpleString With {.Value = "0"},
         New SimpleString With {.Value = "0"}}

    Dim counter As Integer = 0

    Dim newIntegerList As IEnumerable(Of SimpleString) =
        (From i In stringList
        Select New SimpleString With
            {
                .Value = (counter = counter + 1).ToString
            })
End Sub

The above does not work.

Rules:

  • No C# (I know it can be done in C#, but this is VB.NET)
  • No method syntax (my query is complex, so query syntax is preferable)
  • No ToList or List(Of) (I don't use Lists anywhere in my application and I'd rather not start for consistency. Also IEnumerable means queries are not executed until necessary)
  • No loops (I'm not using concrete classes. Also consistency as I minimise the use of loops and primarily use LINQ)
Rowan Freeman
  • 15,724
  • 11
  • 69
  • 100
  • 1
    Why would you *want* to do this without using loops? If you were to explain where the constraints *came from* rather than just arbitrary rules, you'd be likely to get more insightful answers. – Jon Skeet Apr 15 '13 at 06:02
  • Sorry, I've learned through experience to get to the point at SO. I'll rephrase my question. The main reason is I'm curious to see if it can be done, but there are others. – Rowan Freeman Apr 15 '13 at 06:10

2 Answers2

1

Because assignment and equals operators in VB.NET are exactly the same, you cannot do VB.NET equivalent of:

Value = (counter = counter + 1).ToString()

To increment a variable and print it as string.

However, you could write helper method that takes an Integer ByRef, increments it and returns back:

Public Function Increment(ByRef value As Integer) As Integer
    value = value + 1
    Return value
End Function

And use it within your query:

Dim newIntegerList As IEnumerable(Of SimpleString) =
    (From i In stringList
    Select New SimpleString With
        {
            .Value = Increment(counter).ToString
        })

But I have to say, I really don't understand your rules at all ...

MarcinJuraszek
  • 124,003
  • 15
  • 196
  • 263
0

Just for fun, in addition to Marcin's correct answer, you could use an enumerator and produce a side-effect with a Let-clause:

Dim gen = Enumerable.Range(1, Int32.MaxValue).GetEnumerator()
Dim newIntegerList As IEnumerable(Of SimpleString) = _
    (From i In stringList
     Let tmp = gen.MoveNext()
     Select New SimpleString With
            {
                .Value = gen.Current()
            })

Also, just for the record, using the method syntax (which I would prefer in this situation):

Dim newIntegerList As IEnumerable(Of SimpleString) = _
    stringList.Select(Function(v, i) New SimpleString With
        {
            .Value = i + 1
        })
Community
  • 1
  • 1
sloth
  • 99,095
  • 21
  • 171
  • 219