5
       'Why doesn't this work?
    Dim myStrings As String() = New String() {string1, string2, string3,}
    For Each s As String In myStrings
        If String.IsNullOrEmpty(s) Then
            s = ""
        End If
        s = "-" & s.Trim() & "-"
    Next

If string1 contains "foo", my intention is that string1 contains "-foo-" after the loop executes. How can I make this work?

I'm guessing that this code makes copies of my strings and modifies those. How can I modify my strings in a loop?

Update I've modified the code to use array indexes:

    ' It still doesn't work.
    Dim myStrings As String() = New String() {string1, string2, string3}
    For i As Integer = 0 To myStrings.Count() - 1
        If String.IsNullOrEmpty(myStringss(i)) Then
            myStringss(i) = ""
        End If
        myStrings(i) = "-" & myStrings(i) & "-"
    Next

The result of this code, referring specifically to the array and index for each element, modifies the array, but my strings still have the same old values. Apparently, initializing an array like this simply copies my values into a new array. How can I modify my original values in a loop?

Emphasis: The array is just for looping purposes. I need to modify string1, string2, and string3 similarly, but once this loop is thru, there is no more use for the array. Oh, and my real code has more than 3 strings.

Let me just say that if I were using a language with more pointers and references, I think I would simply have an array of pointers that point to string1, string2, andstring3`. It seems redundant to copy these strings into an array.

4
  • 1
    Shouldn't it be "For Each s As String In myStrings" Commented Jul 21, 2010 at 13:34
  • @Gage: Yes, it should. Write it as an answer, so it can be marked as correct =) Commented Jul 21, 2010 at 13:36
  • @Tomas that's not an answer, that's merely a small fix. Commented Jul 21, 2010 at 13:38
  • 3
    I'm afraid that you cannot modify the original values in this way (see my answer) - can you post some more information about what the stringN values are, and why you need to loop through them in this way? It sounds to me like you would be better served using a collection instead of many strings, possibly a Dictionary. Commented Jul 21, 2010 at 14:00

10 Answers 10

5

This example is in C# but the same principle applies.

string[] myStrings = new string[] { "temp", "temp2", "temp3" };
myStrings = myStrings.Select(x => "-" + x + "-").ToArray();

Output:

"-temp-" "-temp2-" "-temp3-"

Link to the MSDN article: http://msdn.microsoft.com/en-us/library/bb548891.aspx

You can also use a delegate function to check whether the string is empty. Will work on providing a VB solution and edit when I get it

EDIT:

Dim myStrings As String() = _
        {"apple", "banana", "mango", Nothing, "passionfruit", "grape"}
    myStrings = _
        myStrings.Select(Function(fruit) ("-" & fruit & "-")).ToArray()

Output:

"-apple-" "-banana-" "-mango-" "--" "-passionfruit-" "-grape-"

EDIT 2: Does the same thing as the first edit but more readable

Private Function TESTER(ByVal fruit As String) As String
    Return "-" & fruit & "-"
End Function

Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs)              Handles MyBase.Load
    Dim myStrings As String() = _
       New String() {"apple", "banana", "mango", Nothing, "passionfruit", "grape"}
    myStrings = _
        myStrings.Select(AddressOf TESTER).ToArray()
End Sub
Sign up to request clarification or add additional context in comments.

2 Comments

what would this look like if Function(fruit) was several lines of code instead of just one line?
@Rice Flour Cookies, that depends on what your trying to do. I'm used to using a delegate function but thats only in C#. I'll take a look at it. What are you trying to do with the strings?
3

Use a For/Next and in the end, myStrings(i) = s to save the result.

10 Comments

i is not defined anywhere. Did you do that just to test me?
The reason this is correct is that for/each gives you a copy of each element. Strings are referenced objects but have value-like semantics, so the changes you're making ((technically, just replacing one value with another) are to your local copy.
@Rice: The i would be the index of the for/next loop Henk refers to.
@Kragen: He wants to alter each of the elements by adding a dash before and after (while converting null to empty and trimming whitespace).
@Steven Like I said, they want the values of stringN to be updated, not the values of the elements of the array - look at the update to the question.
|
2

This doesn't work because strings are immutable in .Net - you can't change the value of string1 without explicitly setting string1 to some value, i.e. by doing:

string1 = "Blah";

(Note that you can change the value of the ith string value in the myString array by (for example) using for instead of foreach, however from what I gather this isn't what you want to do)

To solve your problem you are going to need to given a better idea of what problem you are trying to solve, for example you could avoid the need to modify string references in this way by tweaking your interface (see this question for inspiration)

1 Comment

@Henk sounds to me like they want to change the value of string1, not the contents of the array.
2

Given your most recent update, what you ask is not possible.

Strings follow value semantics, so anything you do to the string in the array has no effect on the original string. The closest you can come to a referenced string is StringBuilder, but it's not particularly easy to use in the way you want.

You need to take a step back and ask yourself why you're trying to do things this way; in other words, what your actual goal is. Once you share that, perhaps we can find a solution that works.

3 Comments

string1, string2, and string3 are all passed as parameters to a function. I want to use them for different things within the function, but I first wish to apply a common operation to them.
Ok, then write a Shared helper method that takes a string by reference and makes the changes. Then, at the top of your main method, simply call the helper once for each parameter. I know there's no loop, but then again, you were filling an array without a loop, too.
Per your response to DrunkenBeard, the helper method could easily be implemented as an anonymous delegate without a closure.
2

Depending upon the nature of your collection, you could store unity-length arrays in it rather than strings. If you did that, you would then be able to change the 0th element of each array to update it.

For example, you could have a Dictionary(Of String, String()) which mapped strings onto string arrays. If single-item arrays were stored in the dictionary, you could easily alter the 0th item of any of them without disturbing the dictionary. Note that you should not do that with the dictionary keys, since the dictionary would not be able to search based upon the content of the strings.

BTW, I've sometimes wished for a collection class whose enumerator would return an object which could be used to request an alteration to the collection without jinxing the enumeration. Not sure how to manage such a thing without having to code the collection from scratch.

Comments

1

Iteration variables are immutable. Either use a "classic" loop or another array to store your strings.

10 Comments

Again ? If it's a reference to your comment about strings not being immutable, I'd agree that it's not the problem here. AFAIK Iteration variables (of any type) are read only, and that's the problem with the code above. Using a For/Next loop would solve it.
@DrunkenBeard, I've posted some code using a For/Next loop that seems like it should solve the problem, but the result is that only the array is changed. StringN is still the old value. Can you suggest anything?
@Henk msdn.microsoft.com/en-us/library/aa664754%28v=VS.71%29.aspx "A compile-time error occurs if the embedded statement attempts to modify the iteration variable"
To clarify why this is about value semantics, not mutability, consider that if he were to pass in an array of mutable struct instances, anything he does to the values in the array would have no effect on the values used to initialize the array.
@Steven, yep I totally agree. After the edit it's clear that this isn't about mutability but value semantics. My answer was directed to Henk saying that iteration variables were not immutable.
|
1

It doesn't work because strings are immutable.

Try this instead.

For x As Integer = 0 To myStrings.Length - 1
   myStrings(x) = "new string"
Next

Edit after the update.

I'm not sure it's possible to do this.

Maybe you could just write a function?

string1 = MyFunction(string1)

13 Comments

I don't think this has anything to do with the immutability of strings.
I'm going to rephrase: the issue isn't that strings are immutable, it's that they have value semantics. The s contains a perfectly good copy of the value, and all of the changes happen to the s. They just have no bearing on the corresponding element in myStrings.
@Henk: Yes, Chris' code does solve the problem. I'm sorry if I didn't make that clear.
Arrggh, value semantics! You would think that changing a set of strings would be such a simple tasks, but no matter how I group the strings, it copies the strings into the group so that only the copies are modified!
@Chris: Yes, but string is a strange case, where it is actually a reference but is designed to work almost exactly as if it were a value. Part of the trick is that it's immutable: you replace the string with a new one instead of actually changing the string itself. Another part is that the equality operators compare on content, not location. For reference objects, the default equality just tells us whether we're comparing something with itself.
|
1

After your edit I don't think you can do this the way you want to. I think you're better off copying your strings to the array and working with the array. Instead of having string1, string2, etc ... you'd have array[0], array[1], etc ...

Is there anything preventing you from doing so ?

1 Comment

I would prefer not to have to write another function to do this. I would like all the functionality in a single function. It looks like I can do this with "anonymous delegates" in .net 4.0
1

This would be easily encapsulated into a ParamArray of ByRef parameters, but that isn't an option
:-(

So you seem to have to do it manually:

Imports System.Runtime.CompilerServices

Module Module1

Sub Main()
    Dim String1 = "foo"
    Dim String2 = ""
    Dim String3 As String = Nothing
    Dim strings() = New StrongBox(Of String)() {New StrongBox(Of String)(String1), New StrongBox(Of String)(String2), New StrongBox(Of String)(String3)}
    Modify(strings)
    String1 = strings(0).Value
    String2 = strings(1).Value
    String3 = strings(2).Value
    Console.WriteLine("'{0}' '{1}' '{2}'", String1, String2, If(String3, "NOTHING"))
    Console.ReadLine()
End Sub

Sub Modify(ByVal ParamArray myStrings() As StrongBox(Of String))
    For i As Integer = 0 To myStrings.Count() - 1
        If String.IsNullOrEmpty(myStrings(i).Value) Then
            myStrings(i).Value = ""
        End If
        myStrings(i).Value = "-" & myStrings(i).Value & "-"
    Next
End Sub

End Module

EDIT: Note that it is simpler to do something like this (it just doesn't supply anything like what the question is asking for):

Module Module1

Sub Main()
    Dim String1 = "foo"
    Dim String2 = ""
    Dim String3 As String = Nothing
    Modify(String1)
    Modify(String2)
    Modify(String3)
    Console.WriteLine("'{0}' '{1}' '{2}'", String1, String2, If(String3, "NOTHING"))
    Console.ReadLine()
End Sub

Sub Modify(ByRef myString As String)
    If String.IsNullOrEmpty(myString) Then
        myString = ""
    End If
    myString = "-" & myString & "-"
End Sub

End Module

Comments

0

As suggested in @Justin's comment, an alternative is to use a Dictionary and VB's With and ! syntax.

Module Module1

Sub Main()
    Dim strings As New Dictionary(Of String, String)
    With strings
        !String1 = "foo"
        !String2 = ""
        !String3 = Nothing
        Console.WriteLine("'{0}' '{1}' '{2}'", !String1, !String2, If(!String3, "NOTHING"))
        Modify(strings)
        Console.WriteLine("'{0}' '{1}' '{2}'", !String1, !String2, If(!String3, "NOTHING"))
        ModifySome(strings, "String1", "String2")
        Console.WriteLine("'{0}' '{1}' '{2}'", !String1, !String2, If(!String3, "NOTHING"))
    End With
    Console.ReadLine()
End Sub

Sub Modify(ByVal myStrings As Dictionary(Of String, String))
    ModifySome(myStrings, myStrings.Keys.ToArray)
End Sub

Sub ModifySome(ByVal myStrings As Dictionary(Of String, String), ByVal ParamArray someStrings() As String)
    For Each s As String In someStrings
        If String.IsNullOrEmpty(myStrings(s)) Then
            myStrings(s) = ""
        End If
        myStrings(s) = "-" & myStrings(s) & "-"
    Next
End Sub

End Module

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.