Using a 'foreach' loop with stringArray in C# - c#

I am writing a program which should display the items from an array in a foreach loop.
I wanted to change the elements of the array by adding a string "sad" to each element, but when run the program the array stays the same.
namespace ConsoleApplication3
{
class Program
{
static void Main(string[] args)
{
string[] stringArray = {"hey", "Tom"};
for (int i = 0; i < stringArray.Length; i++ )
{
stringArray[i] += " dad";
Console.WriteLine(stringArray[i]);
}
Array.Resize(ref stringArray, stringArray.Length + 1);
// Add bob to the last element of the array
stringArray[stringArray.Length - 1] =" bob";
foreach (string s in stringArray)
{
string b = s + "sad";
Console.WriteLine(s);
//Console.WriteLine(stringArray);
}
}
}
}

foreach (string s in stringArray)
{
string b = s + "sad";
// ...
}
Here you are creating a new string, completely unrelated to the string in the string-array. You haven't changed the old string (you can't; strings are immutable). You then simply drop this new longer string on the floor - you aren't updating the array etc.
Try instead something like:
for(int i = 0 ; i < stringArray.Length ; i++)
{
stringArray[i] = stringArray[i] + "sad";
}
This replaces every item in the array with a new string. Note that you can't update a list/collection/array etc while iterating with foreach - that can break the iterator. Hence the for loop instead.

Apart from what Chris said, you could simply use LINQ to achieve what you want:
string[] newStringArray = stringArray
.Select(s => s + "sad")
.ToArray();

string b = s + "sad";
Console.WriteLine(s);
//Console.WriteLine(stringArray);
At no point in your code do you alter values in the array. You create a new string from each value in the array, concatenated with the string "sad".
Solution
You can not alter a for-each variable. You'll get a message like:
Cannot assign to 's' because it is a 'foreach iteration variable'.
Instead, settle for a simple for loop.
for(int x = 0; x < stringArray.length; x++)
{
stringArray[x] = stringArray[x] + "sad";
}

Look at this part of the code:
string b = s + "sad";
Console.WriteLine(s);
You are concatenating the string in s with the string "sad", and storing in the variable b. Then you display the content of the variable s. If you would display the content of the variable b isntead, there would be a sad at the end of each string.

Related

Function which takes a string as input and returns an array of strings as follows ABC(abcde) should return [Abcde, aBcde, abCde, abcDe, abcdE]

I am doing this in this way but its remove string previous characters, its out put is (Magic,Agic,Gic,Ic,C) but I want the whole string to be concate before and after.
public string[] Transform(string st)
{
string[] arr = new string[st.Length];
string[] arr1 = new string[st.Length];
for (int x = 0; x < st.Length; x++)
{
arr1[x] = char.ToLower(st[x]) + "".ToString();
}
for (int i = 0; i < st.Length; i++)
{
string st1 = "";
{
st1 = char.ToUpper(st[i]) + st.Substring(i + 1);
}
arr[i] = st1;
}
return arr;
}
You can do this with a single loop:
public static string[] Transform(string str)
{
var strs = new List<string>();
var sb = new StringBuilder();
for (int i = 0; i < str.Length; i++)
{
sb.Clear();
sb.Append(str);
sb[i] = char.ToUpper(str[i]);
strs.Add(sb.ToString());
}
return strs.ToArray();
}
What this does is adds the str to a StringBuilder and then modifies the indexed character with the upper case version of that character. For example, the input abcde will give:
Abcde
aBcde
abCde
abcDe
abcdE
Try it out on DotNetFiddle
If you wanted to get really fancy I'm sure there is some convoluted LINQ that can do the same, but this gives you a basic framework for how it can work.
You forgot to add left part of the string. Try to do like this:
st1 = st.ToLower().Substring + char.ToUpper(st[i]) + st.Substring(i + 1);
Here. This is twice as fast as the method that uses a string builder and a List
public static string[] Transform(string str)
{
var strs = new string [str.Length];
var sb = str.ToCharArray();
char oldCh;
for (int i = 0; i < str.Length; i++)
{
oldCh = sb[i];
sb[i] = char.ToUpper(sb[i]);
strs[i] = new string (sb);
sb[i] = oldCh;
}
return strs;
}
There's no need to clear and keep reading the string to the string builder. We also know the size of the array so that can be allocated at the start.
I wrote an answer for your questions (it's second code snippet), you can modify it for your needs, like changing the return type to string[], or use ToArray() extension method if you wanna stick with it. I think it's more readable this way.
I decided to put a the end little profiler to check CPU usage and memory compared to #Ron Beyer answer.
Here is my first attempt:
public static void Main()
{
var result = Transform("abcde");
result.ToList().ForEach(WriteLine);
}
public static IEnumerable<string> Transform(string str)
{
foreach (var w in str)
{
var split = str.Split(w);
yield return split[0] + char.ToUpper(w) + split[1];
}
}
Result:
Abcde
aBcde
abCde
abcDe
abcdE
Code fiddle https://dotnetfiddle.net/gnsAGX
There is one huge drawback of that code above, it works only if the passed word has unique letters. Therefore "aaaaa" won't produce proper result.
Here is my second successful attempt that seems works with any string input. I used one instance of StringBuilder to decrease the number of objects that would need to be created and manage on one instance, instead of so much copying objects so it's more optimized.
public static void Main()
{
var result = Transform("aaaaa");
result.ToList().ForEach(WriteLine);
}
public static IEnumerable<string> Transform(string str)
{
var result = new StringBuilder(str.ToLower());
for( int i = 0; i < str.Length; i++)
{
result[i] = char.ToUpper(str[i]);
yield return result.ToString();
result[i] = char.ToLower(str[i]);
}
}
Result:
Aaaaa
aAaaa
aaAaa
aaaAa
aaaaA
Code fiddle: https://dotnetfiddle.net/tzhXtP
Measuring execute time and memory uses.
I will use dotnetfiddle.net status panel, to make it easier.
Fiddle has few limitations like time execution of code 10 sec and used memory
besides differences are very significant.
I tested programs with 14 000 repetitions, my code additionally changes the output to array[].
My answer (https://dotnetfiddle.net/1fLVw9)
Last Run: 12:23:09 pm
Compile: 0.046s
Execute: 7.563s
Memory: 16.22Gb
CPU: 7.609s
Compared answer (https://dotnetfiddle.net/Zc88F2)
Compile: 0.031s
Execute: 9.953s
Memory: 16.22Gb
CPU: 9.938s
It slightly reduces the execution time.
Hope this helps!
public static string[] Transform(string str)
{
var strs = new string [str.Length];
var sb = str.ToCharArray();
char oldCh;
for (int i = 0; i < str.Length; i++)
{
oldCh = sb[i];
sb[i] = char.ToUpper(sb[i]);
strs[i] = new string (sb);
sb[i] = oldCh;
}
return strs;
}

Find and count latter pair from a string by alphabetical order

I am working on a small project which is in C# where I want to find and count the latter pairs which comes in alphabetical order by ignoring spaces and special characters.
e.g.
This is a absolutely easy.
Here my output should be
hi 1
ab 1
I refereed This post but not getting exact idea for pair latter count.
First I remove the spaces and special characters as you specified by simply going though the string and checking whether the current character is a letter:
private static string GetLetters(string s)
{
string newString = "";
foreach (var item in s)
{
if (char.IsLetter(item))
{
newString += item;
}
}
return newString;
}
Than I wrote a method which checks if the next letter is in alphabetical order using simple logic. I lower the character's case and check if the current character's ASCII code + 1 is equal to the next one's. If it is, of course they are the same:
private static string[] GetLetterPairsInAlphabeticalOrder(string s)
{
List<string> pairs = new List<string>();
for (int i = 0; i < s.Length - 1; i++)
{
if (char.ToLower(s[i]) + 1 == char.ToLower(s[i + 1]))
{
pairs.Add(s[i].ToString() + s[i+1].ToString());
}
}
return pairs.ToArray();
}
Here is how the main method will look like:
static void Main()
{
string s = "This is a absolutely easy.";
s = GetLetters(s);
string[] pairOfLetters = GetLetterPairsInAlphabeticalOrder(s);
foreach (var item in arr)
{
Console.WriteLine(item);
}
}
First, I would normalize the string to reduce confusion from special characters like this:
string str = "This is a absolutely easy.";
Regex rgx = new Regex("[^a-zA-Z]");
str = rgx.Replace(str, "");
str = str.ToLower();
Then, I would loop over all of the characters in the string and see if their neighbor is the next letter in the alphabet.
Dictionary<string, int> counts = new Dictionary<string, int>();
for (int i = 0; i < str.Length - 1; i++)
{
if (str[i+1] == (char)(str[i]+1))
{
string index = "" + str[i] + str[i+1];
if (!counts.ContainsKey(index))
counts.Add(index, 0);
counts[index]++;
}
}
Printing the counts from there is pretty straightforward.
foreach (string s in counts.Keys)
{
Console.WriteLine(s + " " + counts[s]);
}

get foreach sequence number on an array

I have an array s[],I'm setting it with:
string [] s;
s = data.Split(',');
after I can getting elements from s with foreach:
foreach (string c in s)
{
list.Items.Add(c);
}
but I want to write the seqeunce of c near to c value i.e it'll show in list:
0 hello
1 world
2 earth
I'm not using a counter in foreach,is there another way?
You have to use a counter. You can use one in foreach, or use a for loop and use its counter.
Edit: well if you start with an empty list you could use list.Items.Count in the loop to print the current count of items in the list although this is really not a good way to do that.
// ugly
foreach (string c in s)
{
list.Items.Add(list.Items.Count + " " + c);
}
The obvious thing would be to use a regular loop:
for (int i = 0; i < c.Length; i++) {
list.Items.Add(i.ToString() + " " + c[i]);
}
If you absolutely want to use foreach and no counter variable, you can use Select to bundle each string with its index:
foreach (var c in s.Select((str, i) => new { Value = str, Index = i })) {
list.Items.Add(c.Index.ToString() + " " + c.Value);
}
no there is no other way with given your code.
either you do this:
string [] s= {"0 Hello","1 World", "2 earth"};
//your simple foreach loop
or you do this:
int counter=0;
foreach (string c in s)
{
list.Items.Add(counter++ + " " + c);
}
or change your code, use a for loop
foreach (int i=0;i<s.Length;i++)
{
list.Items.Add(i + " " + c[i]);
}

Edit array elements

I have an array of drive letters and I need to append a colon to each letter and then pass the array to another function. Can I do this or do I need to create a new array? Or maybe not an array at all but some kind of List instead?
string source = "C|D|E";
string[] sourcearray = source.Split('|');
foreach (string driveletter in sourcearray)
{
//need to append ":" to each drive letter
}
EDIT: There are times when the source array could end in a pipe:
string source = "C|D|E|";
When that happens the last element in the array will be a colon if I use a common for loop, and I can't have this. How best to handle this? When this happens the final array needs to look like:
C: D: E:
Thanks.
Strings are immutable, so you can't change the string instance but you must change the array slots with new strings:
string source = "C|D|E";
string[] sourcearray = source.Split(new []{'|'}, StringSplitOptions.RemoveEmptyEntries);
for(int i=0; i < sourcearray.Length; i++)
{
sourcearray[i] = sourcearray[i] + ":";
}
Replace your for-loop with
string[] resultArray = sourcearray.Select(s => s + ":").ToArray();
Re the Edit:
string source = "C|D|E|";
The best solution here is to this is a special variation of the string.Split() method. Unfortunately that one requires an array of separator chars, so we get:
sourceArray = source.Split(new char[] {'|'},
StringSplitOptions.RemoveEmptyEntries);
for (var i = 0; i < sourcearray.Length; i++)
{
sourceArray[i] += ":";
}
string[] sourcearray = source.Split('|').Select(s => s + ":").ToArray();
var newArray = source.Split('|').Select(s => s + ":").ToArray();

displaying characters and how many times they appear?

I get a string from the user and then put it in a char array. Now I want to display all the characters in the string along with how many times they appear. My code is as follows Please Correct me ?
using System;
class count
{
public void charcount()
{
int i ;
int count = 0;
string s;
Console.WriteLine("Enter the String:");
s = Console.ReadLine();
char[] carr = s.ToCharArray();
for(i = 0; i < carr.Length; i++)
{
for(int j = 1; j < carr.Length; j++)
{
if(carr[j] == carr[i])
{
count++;
}
else
{
return;
}
Console.WriteLine("The Character " + carr[i] + " appears " + count);
}
}
}
static void Main()
{
count obj = new count();
obj.charcount();
}
}
Well, your code will at least have problems due to the fact that you don't build a list of unique characters, you find them in the original string. Any string with characters that appear multiple times will show odd results.
Here's a LINQ expression that calculates the information for you (you can run this in LINQPad to immediately see the results):
void Main()
{
string s = "This is a test, with multiple characters";
var statistics =
from c in s
group c by c into g
select new { g.Key, count = g.Count() };
var mostFrequestFirst =
from entry in statistics
orderby entry.count descending
select entry;
foreach (var entry in mostFrequestFirst)
{
Debug.WriteLine("{0}: {1}", entry.Key, entry.count);
}
}
Output:
: 6 <-- space
t: 5
i: 4
s: 4
h: 3
a: 3
e: 3
l: 2
c: 2
r: 2
T: 1
,: 1
w: 1
m: 1
u: 1
p: 1
If you can't use LINQ, here's an example that doesn't use that:
void Main()
{
string s = "This is a test, with multiple characters";
var occurances = new Dictionary<char, int>();
foreach (char c in s)
{
if (occurances.ContainsKey(c))
occurances[c] = occurances[c] + 1;
else
occurances[c] = 1;
}
foreach (var entry in occurances)
{
Debug.WriteLine("{0}: {1}", entry.Key, entry.Value);
}
}
It looks like you want an outer loop and an inner loop, and for each char in the array, you want to compare to each that follows with int j = 1. In that case, you want int j = i + 1 in the inner loop:
for (int i = 0; i < carr.Length; i++)
{
for (int j = i + 1; j < carr.Length; j++)
{
}
}
But your return statement exits the function right in the middle of things. You need to let the loops complete, so you want to remove that return.
Your Console.WriteLine executes on every iteration of the inner loop, but you really only want it to iterate on the outer loop -- once for each character of the string and not once for every combination of i and j. So you need to push that to the outer loop, outside of the inner loop.
Also, you need to reset the count every time you begin another iteration of the outer loop, because you are counting again, and, you want to start counting at 1 not zero when you find a character because it just appeared once as you first reach it.
And as Lasse points out, you'll get strange output when you hit the same character as you move along the outer loop. An easy way to prevent that is to set the further (rightwards) char[j] to '\0' (null character) on every match, and then in the outer loop, ignore null characters in your counting for example by using continue, effectively culling them as you go along:
for(int i = 0; i < carr.Length; i++)
{
if (carr[i] == '\0')
{
continue; // skip any further chars we've already set to null char
}
int count = 1;
for (int j = i + 1; j < carr.Length; j++)
{
if(carr[j] == carr[i])
{
carr[j] = '\0'; // don't look for this char again later
count++;
}
}
Console.WriteLine("The Character " + carr[i] + " appears " + count);
}
My first thought would be to use a Dictionary as Daniel suggests, like this:
var dict = new Dictionary<char, int>();
string s = "This is a test, with multiple characters";
foreach (var c in s)
{
if (dict.ContainsKey(c))
{
dict[c]++;
}
else
{
dict[c] = 1;
}
}
foreach (var k in dict.Keys)
{
Console.WriteLine("{0}: {1}", k, dict[k]);
}
But I like the elegant LINQ solutions.
If you would have tested your code, you would have realized, that the code is very wrong.
Some of its problems:
You have only one count variable, although you want to count the occurences of all characters in your string
You are comparing the string with itself and return from your method, as soon, as the characters don't match.
The right way would be to use a Dictionary<char, int> to hold the count for each character, something like this:
var counts = new Dictionary<char, int>();
foreach(var c in s)
{
int count;
if(!counts.TryGetValue(c, out count))
{
counts.Add(c, 1);
}
else
{
++counts[c];
}
}
I didn't use LINQ on purpose, because I don't think you would understand that code. That's no offence.
If you want to go the LINQ way, this is a fairly brief way to do it (which I realize is pretty much the same as Lasse V. Karlsen's answer, only using different syntax):
var s = Console.ReadLine();
foreach (var group in s.GroupBy(c => c).OrderByDescending(g => g.Count()))
{
Console.WriteLine(" {0}: {1}", group.Key, group.Count());
}
The logic is the same whatever approach you use:
Identify each unique character
Count how many times each character occurs in the text
Output the result
In my code sample, s.GroupBy(c => c) takes care of the first two steps. The call OrderByDescending(g => g.Count()) will just sort the result so that more frequent characters come first. Each element in the result has a Key property (the character) and (amongst others) a Count() method that will return the number of occurrences for that character.

Categories