Can I use StringBuilder elements in a foreach? - c#

Since I'm using .NET 1.1, I can't use a generic List of string, as generics were not part of the language yet. So I'm trying to use a StringBuilder, but get this err msg:
"foreach statement cannot operate on variables of type 'System.Text.StringBuilder' because 'System.Text.StringBuilder' does not contain a definition for 'GetEnumerator', or it is inaccessible"
with this code:
public StringBuilder linesToSend;
. . .
foreach (string _line in this.linesToSend)
{
serialPort.Write(_line);
}
Is there something wrong with my code, or is StringBuilder really disallowed from foreach loops? If the latter, is String[] my best recourse?

Old question, I know, but something potentially useful:
If each of your strings were built with .AppendLine or you inserted a new line, you can do
string[] delim = { Environment.NewLine, "\n" }; // "\n" added in case you manually appended a newline
string[] lines = StringBuilder.ToString().Split(delim, StringSplitOptions.None);
foreach(string line in lines){
// Do something
}

A StringBuilder doesn't store the lines that you append. It simply is used to build the final string. Assuming you've added everything to the StringBuilder already, you can do:
// Write the complete string to the serialPort
serialPort.Write(linesToSend.ToString());

This is correct. A StringBuilder is designed to help you build one final output string as the others have stated.
If you have a variable number of strings you need to work on, you can use an ArrayList and iterate over that.
ArrayList strings = new ArrayList();
// populate the list
foreach (string str in strings) {
// do what you need to.
}
If you're afraid that the array list might contain other objects (as it isn't strongly typed) you can cast it safely instead:
foreach (object obj in strings) {
string str = obj as string;
// If null strings aren't allowed, you can use the following
// to skip to the next element.
if (str == null) {
continue;
}
}

A StringBuilder is building just one string, so how could you foreach it to get a whole sequence of strings?
If you need to write line by line, maybe use an ArrayList, add each line string to that, and foreach with string as the foreach variable type (Object will be cast to String). Or even better, use StringCollection (thank to comment by Anthony Pegram, to the original question; I had forgotten this class).
But why not upgrade to a newer version of .NET?

The foreach loop works by calling the GetEnumerator from the interface IEnumerable which will return an enumerator that foreach uses to get the next element of the object.
StringBuilder does not implement IEnumerable or IEnumerable<T> which would allow the foreach to work. You are better off using a string[] or StringCollection in this case and when you are done you can concatenate the collection using a StringBuilder.
ex:
StringBuilder stringBuilder = new StringBuilder();
foreach(string line in array)
{
serialPort.Write(line);
stringBuilder.Append(line);
}

What you're looking for is an array of strings if you know the number of elements, or else a dictionary.

Related

How to change string into a list of characters in C# for beginners?

I am currently trying to use Codecademy to learn how to use C# yet the last 'test' for the very second lesson asks us to convert a string to a list. I looked at a forum and it said you had to use loops which was not taught in the course yet, yet I wanted to use a loop anyway, how could I create the list with the for loop which possibly needs fixing? (And maybe help to check whether or not the other code is correct as it asks to convert bool to string and a random data type to another which I chose byte for.) Thanks.
bool pick = true;
byte number = 5;
string myTest = "Ping Pong";
Console.WriteLine(Convert.ToString(pick));
Console.WriteLine(Convert.ToInt32(number));
for ((char(myTest));)
{
Console.WriteLine(i);
}
You use string.ToCharArray to convert the string into an array of characters.
However you don't need to do that just to iterate over it, string implements IEnumerable<char>, so you can iterate over it directly.
Also for ((char(myTest));) makes absolutely no sense.
An string is already a character array and because System.String implements IEnumerable<char> you can just loop it:
/*
References you need:
using System;
using System.Collections.Generic;
using System.Linq;
*/
string myTest = "Ping Pong";
//looping a string
foreach (char character in myTest)
{
Console.WriteLine(character);
}
//Explicit converting a string to list of chars
var listChars = new List<char>();
listChars = myTest.ToList();
foreach (char character in listChars)
{
Console.WriteLine(character);
}

How to store text from a file-list into a variable in c#

Hi I am new to programming. I would like to read a text file and take the values ( strings ) and store each character of the string in an array individually. I have used a list to take in the vales from the text file. I am finding it difficult to move them into an array and then use those values in my program. Please find me a solution if possible. Thanking you in advance.
public class file_IO
{
string[] letters = new string[] //I would like to store it in this variable
public void File_Reader()
{
string filepath = #"env.txt"; //Variable to hold string
List<string> file_lines = File.ReadAllLines(filepath).ToList();//returns array of strings into List
foreach (string line in file_lines)
{
}
}
}
Hope this will work for you!.
public char[] File_Reader()
{
string filepath = #"env.txt"; //Variable to hold string
StreamReader sr = new StreamReader(filepath);
string fileContentInString = sr.ReadToEnd();
sr.Close();
return fileContentInString.ToCharArray();
}
List<List<char>> linesAsChars = File.ReadAllLines(filepath)
.Select(l => l.ToList())
.ToList();
This will get a List of List of chars.
string implements IEnumerable<char>, so with ToList each line in the file is translated to List<char>.
Solution to "store each character of the string in an array individually" is fairly easy because string is in fact an array of char. You can do this using something like this :
char[] letters;
public void File_Reader()
{
string filepath = #"env.txt";
letters = File.ReadAllText(filePath).ToArray();
}
I'm not really sure if I have understood your question properly, but from what I have read, I will assume that you want an array of lines (which are strings).
In this case, you don't need to do much as the File.ReadAllLines() method naturally outputs an array of string variables.
Remove the for loop and replace
List<string> file_lines = File.ReadAllLines(filepath).ToList();//returns array of strings into List
with:
letters = File.ReadAllLines(filepath)
In case what you want is actually an array of every char value in your file, I would refer to #m.rogalski's answer and declare an array of char[], for example, declare:
char[] fileChars;
and then replace the line I mentioned earlier with:
fileChars = readAllText(filePath).toCharArray()
You will notice that you do not need a loop in either of the above situations. Hope I helped.

How to store arraylist items in a string

Just a very small question.
I have a array list named li, where after my conditions I have the contents as:
li[0]="s";
li[1]="a";
li[2]="h";
li[3]="i";
li[4]="4";
Now I wrote the code as:
foreach (string value in li)
{
tb_output.Text = li.ToString();
}
Here, I want that for each list item, the elements should be stored in a string, which I want to display it in a textbox. But i am unable to get "sahil" in tb_output.
Can you tell me where I am wrong. I am unable to take it. I am a beginner, so it is a kind of trouble to me.
If li is a char[], use tb_output.Text = new String(li)
If li is a List<char>, use tb_output.Text = new String(li.ToArray())
If li is a string[] or List<string>, use tb_output.Text = String.Concat(li)
Otherwise, if li contains chars, use tb_output.Text = new String(li.Cast<char>().ToArray())
Otherwise, if li contains string, use tb_output.Text = String.Concat(li.Cast<string>())
You should avoid using ArrayLists whenever possible. Either use List<char> or char[] array. I've used char because you're only holding chars but you can change this to string if you're going to use more than one character.
With a char array, you can simply do this
string myString = new string(li);
Alternatively, you can simply use the String.Concat method and pass in the List or Array.
tb_output.Text = String.Concat(myArrayOrList);
Update for clarification of comment
If you want to use a List<T>, you can do this.
List<char> li = new List<char>() { 's', 'a', 'h', 'i', 'l' };
tb_output.Text = String.Concat(li);
If you really must use an ArrayList here then you can simply convert that ArrayList to an array of chars and use the first method described above (new string(myCharArray))
try
{
tb_output.Text = new string((char[])myArrayList.ToArray(typeof(char)));
}
catch(InvalidCastException ex)
{
//handle any problems with the casting
}
I've added a try..catch block for the ArrayList because if there's an element in the array list that can't be cast to a char then an InvalidCastException is thrown. This isn't generally needed with a List<char> because you know that the list can only have chars in them whereas an ArrayList can have any object type.
Update 2 based on comments
The line new string((char[])myArrayList.ToArray(typeof(char)) can be broken down.
First we are converting the ArrayList to an Array using the the method ToArray()
myArrayList.ToArray();
However, we want to tell the ToArray method to convert every object inside to the ArrayList to a char because, at the moment, the ArrayList is holding object types and not char types. So we pass that information into the method.
myArrayList.ToArray(typeof(char));
We can create a new string from an array of chars by doing
string newString = new string(arrayOfChars);
At the moment we have an Array from the ToArray method but the string constructor here needs an array of chars (char[]) so we cast the Array that we have to a char[] which is why we have
(char[])myArrayList.ToArray(typeof(char));
So we now have a char[] from the original ArrayList and can pass that into the string constructor.
new string((char[])myArrayList.ToArray(typeof(char)));
You still haven't given a reason for why you're using an ArrayList but you'll have to deal with potential performance issues and casting exceptions as you may accidentally put an object into the ArrayList that can't be converted into a char (which is why we have the Try..Catch block).
How about trying
foreach (string value in li)
{
tb_output.Text += value;
}
The other answers should work for your particular question, however, if you want to write to that textbox the contents of li, you should instead do it in this manner.
string word = "";
foreach(string s in li)
{
word += s;
}
tb_output.Text = s;
That way, you clear out the textbox each time you write the array to it.
Better yet, especially if are dealing with a large array, improve performance by using StringBuilder (which you can get by adding "using System.Text;" to the top of your file.
StringBuilder stb = new StringBuilder();
foreach(string s in li)
{
stb.Append(s);
}
tb_output.Text = stb.ToString();
You need to append with +=
foreach (string value in li)
{
tb_output.Text += li.ToString();
}
You can join all elements from an array using String.Join method.
It takes two parameters, the first is: "join with what?", you can join the elements and separate them with a comma for example. The second parameter is your IEnumerable<T>, you can join elements of a List<T> and anything that comes from IEnumerable<T>.
So you could do
tb_output.Text = String.Join("", li);
This will return the string sahi4 as we are joining the array with an empty string.
Or you can use String.Concat already mentioned by keyboardP.
tb_output.Text = String.Concat(li);
Which will concatenate all values.
Alternatively you could build the string using a StringBuilder.
StringBuilder b = new StringBuilder();
foreach (string value in li)
{
sb.Append(value);
}
tb_output.Text = sb.ToString(); // returns the built string
Foreach will return one element at time from your li array and put into value as you named it. Instead of trying to use li.ToString() which will convert the array to a string inside the foreach, you should use value to get the string in each position...
Also, if you are concatenating strings you should use StringBuilder in cases like these, but you could also use the operator +.
stringA = stringA + "B"; // or
stringA += "B";

string.insert multiple values. Is this possible?

Im still learning in C#, and there is one thing i cant really seem to find the answer to.
If i have a string that looks like this "abcdefg012345", and i want to make it look like "ab-cde-fg-012345"
i tought of something like this:
string S1 = "abcdefg012345";
string S2 = S1.Insert(2, "-");
string S3 = S2.Insert(6, "-");
string S4 = S3.Insert.....
...
..
Now i was looking if it would be possible to get this al into 1 line somehow, without having to make all those strings.
I assume this would be possible somehow ?
Whether or not you can make this a one-liner (you can), it will always cause multiple strings to be created, due to the immutability of the String in .NET
If you want to do this somewhat efficiently, without creating multiple strings, you could use a StringBuilder. An extension method could also be useful to make it easier to use.
public static class StringExtensions
{
public static string MultiInsert(this string str, string insertChar, params int[] positions)
{
StringBuilder sb = new StringBuilder(str.Length + (positions.Length*insertChar.Length));
var posLookup = new HashSet<int>(positions);
for(int i=0;i<str.Length;i++)
{
sb.Append(str[i]);
if(posLookup.Contains(i))
sb.Append(insertChar);
}
return sb.ToString();
}
}
Note that this example initialises StringBuilder to the correct length up-front, therefore avoiding the need to grow the StringBuilder.
Usage: "abcdefg012345".MultiInsert("-",2,5); // yields "abc-def-g012345"
Live example: http://rextester.com/EZPQ89741
string S1 = "abcdefg012345".Insert(2, "-").Insert(6, "-")..... ;
If the positions for the inserted strings are constant you could consider using string.Format() method. For example:
string strTarget = String.Format("abc{0}def{0}g012345","-");
string s = "abcdefg012345";
foreach (var index in [2, 6, ...]
{
s = s.Insert(index, "-");
}
I like this
StringBuilder sb = new StringBuilder("abcdefg012345");
sb.Insert(6, '-').Insert(2, '-').ToString();
String s1 = "abcdefg012345";
String seperator = "-";
s1 = s1.Insert(2, seperator).Insert(6, seperator).Insert(9, seperator);
Chaining them like that keeps your line count down. This works because the Insert method returns the string value of s1 with the parameters supplied, then the Insert function is being called on that returned string and so on.
Also it's worth noting that String is a special immutable class so each time you set a value to it, it is being recreated. Also worth noting that String is a special type that allows you to set it to a new instance with calling the constructor on it, the first line above will be under the hood calling the constructor with the text in the speech marks.
Just for the sake of completion and to show the use of the lesser known Aggregate function, here's another one-liner:
string result = new[] { 2, 5, 8, 15 }.Aggregate("abcdefg012345", (s, i) => s.Insert(i, "-"));
result is ab-cd-ef-g01234-5. I wouldn't recommend this variant, though. It's way too hard to grasp on first sight.
Edit: this solution is not valid, anyway, as the "-" will be inserted at the index of the already modified string, not at the positions wrt to the original string. But then again, most of the answers here suffer from the same problem.
You should use a StringBuilder in this case as Strings objects are immutable and your code would essentially create a completely new string for each one of those operations.
http://msdn.microsoft.com/en-us/library/2839d5h5(v=vs.71).aspx
Some more information available here:
http://www.dotnetperls.com/stringbuilder
Example:
namespace ConsoleApplication10
{
class Program
{
static void Main(string[] args)
{
StringBuilder sb = new StringBuilder("abcdefg012345");
sb.Insert(2, '-');
sb.Insert(6, '-');
Console.WriteLine(sb);
Console.Read();
}
}
}
If you really want it on a single line you could simply do something like this:
StringBuilder sb = new StringBuilder("abcdefg012345").Insert(2, '-').Insert(6, '-');

string handling

I would like to know that if I have an english dictionary in a text file what is the best way to check whether a given string is a proper and correct english word. My dictionary contains about 100000 english words and I have to check on an average of 60000 words in one go. I am just looking for the most efficient way. Also should I store all the strings first or I just process them as they are generated.
Thanx
100k is not too great a number, so you can just pop everything in a Hashset<string>.
Hashset lookup is key-based, so it will be lightning fast.
example how this might look in code is:
string[] lines = File.ReadAllLines(#"C:\MyDictionary.txt");
HashSet<string> myDictionary = new HashSet<string>();
foreach (string line in lines)
{
myDictionary.Add(line);
}
string word = "aadvark";
if (myDictionary.Contains(word))
{
Console.WriteLine("There is an aadvark");
}
else
{
Console.WriteLine("The aadvark is a lie");
}
You should probably use HashSet<string> if you're using .NET 3.5 or higher.
Just load the dictionary of valid words into a HashSet<string> and then either use Contains on each candidate string, or use some of the set operators to find all words which aren't valid.
For example:
// There are loads of ways of loading words from a file, of course
var valid = new HashSet<string>(File.ReadAllLines("dictionary.txt"));
var candidates = new HashSet<string>(File.ReadAllLines("candidate.txt"));
var validCandidates = candidates.Intersect(valid);
var invalidCandidates = candidates.Except(valid);
You may also wish to use case-insensitive comparisons or something similar - use the StringComparer static properties to get at appropriate instances of StringComparer which you can pass to the HashSet constructor.
If you're using .NET 2, you can use a Dictionary<string, whatever> as a poor-man's set - basically use whatever you like as the value, and just check for keys.

Categories