String[0] vs ToCharArray then Char[0] - c#

Say I want to get the third letter in a string.
string s = "cats";
what is the difference between using s[2] to get the value,
as I see most examples online use:
char[] c = s.ToCharArray();
char x = c[2];

If you need a char at particular index, use "cats"[2]
If you need the whole string as char array, use "cats".ToCharArray()

The s[2] method simply looks up the character in that position and returns it.
The s.ToCharArray(); method allocates a new char[], then c[2] looks it up in the array.
If you need just a single character, use the s[2] method as the ToCharArray() method is wasteful. If you need all the characters in the string as a char[] then the ToCharArray() method is cleaner and probably faster (I haven't done any benchmarking, so don't hold me to that).
EDIT:
Both MS.NET and Mono's implementations of string.ToCharArray() use unsafe code that pins the internal char and a duplicate char[] and operates on the pointers. This is definitely faster than calling the indexer for every character and is probably faster than using an enumerator to iterate over all the characters. Plus I find it a lot cleaner, especially in the case where it's used as a parameter:
DoSomethingWithCharArray(s.ToCharArray());
vs
int i = 0;
char[] arr = new char[s.Length];
foreach (char c in s)
{
arr[i] = c;
i++;
}
DoSomethingWithCharArray(arr);
or
char[] arr = new char[s.Length];
for (int i = 0; i < s.Length; i++)
{
arr[i] = s[i];
}
DoSeomthingWithCharArray(arr);

The difference is exactly that you're creating a character array unnecessarily. Use s[2].

If you're just reading the character the difference is only a slightly larger memory footprint. However, if you also want to change some characters and retain the original string then utilizing ToCharArray is very usefull.

Related

string[,] array of string arrays equivalent in C

In C#, if I were to create an array of string arrays it is easy as doing:
string[,] array = new string[50,7];
How would I go about doing that in C? I do understand that I should make use of pointers but what I have come up with doesn't seem to work properly.
char *array[50][7];
Please note that I'm not looking to set the elements to constant values, I need to be able to access them/set them in the program again either by means of using the scanf() function or simply with = if possible. What is the simplest way of achieving this?
EDIT: Am I doing something wrong here? The following very simple example crashes the program:
char *username;
printf("Username: ");
scanf("%s", &username);
array[0][0] = malloc(strlen(username) + 1);
strcpy(array[0][0], username);
I have, in fact, added a reference to stdlib.h
There is no easy way :) Since C has no high level string class, at least not without invoking some non-standard library.
To be flexible you would indeed need a 2D array of pointers char *array[50][7];, where every pointer is set to point at the actual string. Upon creating a string, you will have to allocate enough memory to hold it, plus the null terminator, by using malloc(). For example:
array[x][y] = malloc(strlen(the_string) + 1);
assert(array[x][y] != NULL);
It is not possible to copy strings in C with the = assignment operator, so after allocating the memory, you have to copy the string into the allocated memory area by using strcpy.
strcpy(array[x][y], the_string);
The following code crashes as code is attempting to save scanf() input to the place pointed to by username, yet username is not initialized.
char *username;
scanf("%s", &username); // bad
Instead, could use
char username[100];
scanf("%99s", username);
Or better
char username[100];
fgets(username, sizeof username, stdin);
username[strcspn(username, "\n")] = '\0'; // lop off potential \n
It appear OP wants a 50 x 7 array of pointers to C strings allocated like in string[,] array = new string[50,7];
Recall, in C, a string is itself a character array ending with a null character
#include <stdlib.h>
typedef char *a50_7_T[50][7];
a50_7_T *a50_7_alloc(void) {
a50_7_T *a = malloc(sizeof *a);
for (int i=0; i<50; i++) {
for (int j=0; j<7; j++) {
(*a)[i][j] = NULL; // or whatever OP wants as initial state
}
}
return a;
}
void a50_7_free(a50_7_T *a) {
for (int i=0; i<50; i++) {
for (int j=0; j<7; j++) {
free((*a)[i][j]);
}
}
free(a);
}
// Sample usage code
#include <string.h>
void foo(void) {
a50_7_T *a = a50_7_alloc();
printf("Size %zu\n", sizeof *a); // e.g. "Size 1400"
(*a)[0][0] = strcpy(malloc(6), "Hello");
a50_7_free(a);
}
OTOH if OP want to create the array as part of the declaration, what OP did was on the right track.
// Initialize all to zeros, (NULL)
char *array[50][7] = { 0 };
...
array[0][0] = strcpy(malloc(6), "Hello");
...
free(array[0][0]);
The array is ok as that. The problem may come from strings. C 'strings' are very low level, and can't really be compared to C# strings. You will have to manually allocate and deallocate space for them. If you plan on using scanf on them, you can allocate a buffer for each one, but you will have problems if you find a string longer than the buffer. You can assign them with '=', but only if you handle deallocation of the old value. Maybe you can check a library such as 'glib' to do some of the work for you.
Well, you have to decide two things where C# simply doesn't give you a choice (or at least, the standard one is very strongly recommended):
How do you want to represent your 2-dimensional array?
You have the choice between, among others,
a single-dimensional array and explicit pointer-arithmetic,
a pointer to a 2-dimensional array with one fixed dimension,
a pointer to a 1-dimensional array of pointers to 1-dimensional arrays.
How do you want to represent your string?
Decide on the code-unit: char (hopefully 8-bit), wchar16_t, wchar32_t, wchar_t?
Counted strings or 0-terminated?
In a fixed-size-buffer or dynamically allocated?

Property or indexer 'string.this[int]' cannot be assigned to -- it's read only

I didn't get the problem - I was trying to do a simple action:
for(i = x.Length-1, j = 0 ; i >= 0 ; i--, j++)
{
backx[j] = x[i];
}
Both are declared:
String x;
String backx;
What is the problem ? It says the error in the title...
If there is a problem - is there another way to do that?
The result (As the name 'backx' hints) is that backx will contain the string X backwards.
P.S. x is not empty - it contains a substring from another string.
Strings are immutable: you can retrieve the character at a certain position, but you cannot change the character to a new one directly.
Instead you'll have to build a new string with the change. There are several ways to do this, but StringBuilder does the job in a similar fashion to what you already have:
StringBuilder sb = new StringBuilder(backx);
sb[j] = x[i];
backx = sb.ToString();
EDIT: If you take a look at the string public facing API, you'll see this indexer:
public char this[int index] { get; }
This shows that you can "get" a value, but because no "set" is available, you cannot assign values to that indexer.
EDITx2: If you're looking for a way to reverse a string, there are a few different ways, but here's one example with an explanation as to how it works: http://www.dotnetperls.com/reverse-string
String is immutable in .NET - this is why you get the error.
You can get a reverse string with LINQ:
string x = "abcd";
string backx = new string(x.Reverse().ToArray());
Console.WriteLine(backx); // output: "dcba"
String are immuatable. You have convert to Char Array and then you would be able to modify.
Or you can use StringBuilder.
for example
char[] wordArray = word.ToCharArray();
In C# strings are immutable. You cannot "set" Xth character to whatever you want. If yo uwant to construct a new string, or be able to "edit" a string, use i.e. StringBuilder class.
Strings are immutable in C#. You can read more about it here: http://msdn.microsoft.com/en-us/library/362314fe.aspx
Both the variables you have are string while you are treating them as if they were arrays (well, they are). Of course it is a valid statement to access characters from a string through this mechanism, you cannot really assign it that way.
Since you are trying to reverse a string, do take a look at this post. It has lot of information.
public static string ReverseName( string theName)
{
string revName = string.Empty;
foreach (char a in theName)
{
revName = a + revName;
}
return revName;
}
This is simple and does not involve arrays directly.
The code below simply swaps the index of each char in the string which enables you to only have to iterate half way through the original string which is pretty efficient if you're dealing with a lot of characters. The result is the original string reversed. I tested this with a string consisting of 100 characters and it executed in 0.0000021 seconds.
private string ReverseString(string testString)
{
int j = testString.Length - 1;
char[] charArray = new char[testString.Length];
for (int i = 0; i <= j; i++)
{
if (i != j)
{
charArray[i] = testString[j];
charArray[j] = testString[i];
}
j--;
}
return new string(charArray);
}
In case you need to replace e.g. index 2 in string use this (it is ugly, but working and is easily maintainbable)
V1 - you know what you want to put their. Here you saying in pseudocode string[2] = 'R';
row3String.Replace(row3String[2], 'R');
V2 - you need to put their char R or char Y. Here string[2] = 'R' if was 'Y' or if was not stay 'Y' (this one line if needs some form of else)
row3String.Replace(row3String[2], row3String[2].Equals('Y') ? 'R' : 'Y');

Replace a list of invalid character with their valid version (like tr)

I need to do something like this dreamed .trReplace:
str = str.trReplace("áéíüñ","aeiu&");
It should change this string:
a stríng with inválid charactérs
to:
a string with invalid characters
My current ideas are:
str = str.Replace("á","a").Replace("é","e").Replace("í","ï"...
and:
sb = new StringBuilder(str)
sb.Replace("á","a").
sb.Replace("é","e")
sb.Replace("í","ï"...
But I don't think they are efficient for long strings.
Richard has a good answer, but performance may suffer slightly on longer strings (about 25% slower than straight string replace as shown in question). I felt complelled to look in to this a little further. There are actually several good related answers already on StackOverflow as captured below:
Fastest way to remove chars from string
C# Stripping / converting one or more characters
There is also a good article on the CodeProject covering the different options.
http://www.codeproject.com/KB/string/fastestcscaseinsstringrep.aspx
To explain why the function provided in Richards answer gets slower with longer strings is due to the fact that the replacements are happening one character at a time; thus if you have large sequences of non-mapped characters, you are wasting extra cycles while re-appending together the string . As such, if you want to take a few points from the CodePlex Article you end up with a slightly modified version of Richards answer that looks like:
private static readonly Char[] ReplacementChars = new[] { 'á', 'é', 'í', 'ü', 'ñ' };
private static readonly Dictionary<Char, Char> ReplacementMappings = new Dictionary<Char, Char>
{
{ 'á', 'a'},
{ 'é', 'e'},
{ 'í', 'i'},
{ 'ü', 'u'},
{ 'ñ', '&'}
};
private static string Translate(String source)
{
var startIndex = 0;
var currentIndex = 0;
var result = new StringBuilder(source.Length);
while ((currentIndex = source.IndexOfAny(ReplacementChars, startIndex)) != -1)
{
result.Append(source.Substring(startIndex, currentIndex - startIndex));
result.Append(ReplacementMappings[source[currentIndex]]);
startIndex = currentIndex + 1;
}
if (startIndex == 0)
return source;
result.Append(source.Substring(startIndex));
return result.ToString();
}
NOTE Not all edge cases have been tested.
NOTE Could replace ReplacementChars with ReplacementMappings.Keys.ToArray() for a slight cost.
Assuming that NOT every character is a replacement char, then this will actually run slightly faster than straigt string replacements (again about 20%).
That being said, remember when considering performance cost, what we are actually talking about... in this case... the difference between the optimized solution and original solution is about 1 second over 100,000 iterations on a 1,000 character string.
Either way, just wanted to add some information to the answers for this question.
I did something similar for ICAO Passports. The names had to be 'transliterated'. Basically I had a Dictionary of char to char mappings.
Dictionary<char, char> mappings;
static public string Translate(string s)
{
var t = new StringBuilder(s.Length);
foreach (char c in s)
{
char to;
if (mappings.TryGetValue(c, out to))
t.Append(to);
else
t.Append(c);
}
return t.ToString();
}
What you want is a way to go through the string once and do all the replacements. I am not not sure that regex is the best way to do it if you want efficiency. It could very well be that a case switch (for all the characters that you want to replace) in a for loop to test every character is faster. I would profile the two approaches.
It would be better to use an array of char instead of Stringbuilder.
The indexer is faster than calling the Append method, because:
push all local variables to the stack
move to Append address
return to address
pop all local variables from the stack
The example below is about 20 percent faster (depends on your hardware and input string)
static Dictionary<char, char> mappings;
public static string TranslateV2(string s)
{
var len = s.Length;
var array = new char[len];
char c;
for (var index = 0; index < len; index++)
{
c = s[index];
if (mappings.ContainsKey(c))
array[index] = mappings[c];
else
array[index] = c;
}
return new string(array);
}

how to replace characters in a array quickly

I am using a XML Text reader on a XML file that may contain characters that are invalid for the reader. My initial thought was to create my own version of the stream reader and clean out the bad characters but it is severely slowing down my program.
public class ClensingStream : StreamReader
{
private static char[] badChars = { '\x00', '\x09', '\x0A', '\x10' };
//snip
public override int Read(char[] buffer, int index, int count)
{
var tmp = base.Read(buffer, index, count);
for (int i = 0; i < buffer.Length; ++i)
{
//check the element in the buffer to see if it is one of the bad characters.
if(badChars.Contains(buffer[i]))
buffer[i] = ' ';
}
return tmp;
}
}
according to my profiler the code is spending 88% of its time in if(badChars.Contains(buffer[i])) what is the correct way to do this so I am not causing horrible slowness?
The reason that it spends so much time in that line is because the Contains method loops through the array to look for the character.
Put the characters in a HashSet<char> instead:
private static HashSet<char> badChars =
new HashSet<char>(new char[] { '\x00', '\x09', '\x0A', '\x10' });
The code to check if the set contains the character looks the same as when looking in the array, but it uses the hash code of the character to look for it instead of looping through all the items in the array.
Alternatively, you could put the characters in a switch, that way the compiler would create an efficient comparison:
switch (buffer[i]]) {
case '\x00':
case '\x09':
case '\x0A':
case '\x10': buffer[i] = ' '; break;
}
If you have more characters (five or six IIRC), the compiler will actually create a hash table to look up the cases, so that would be similar to using a HashSet.
You might have better results with a switch statement:
switch (buffer[i])
{
case '\x00':
case '\x09':
case '\x0A':
case '\x10':
buffer[i] = ' ';
break;
}
This should be compiled down to fast code by the JIT compiler at runtime. Heck, the compiler might get close too. You don't need a method call this way either.
You could use regular expressions for that which should be optimized. Read the text into a string and use Replace with your characters in the regular expression afterwards.
However, your code also looks fine to me, I guess regex also can't do anything else than searching through your text... and you need to take a string there which you don't need to do with the other options.
you could check how well it optimises with just checking the read chars, making it
for (int i = index; i < index + count; i++){
//etc
}
Don't know if/how much this would help you, you'd have to profile your real world application to check
Try converting the char[] to a string and then using IndexOfAny.
You could use a boolean array
char[] badChars = { '\x00', '\x09', '\x0A', '\x10' };
char maxChar = badChars.Max();
Debug.Assert(maxChar < 256);
bool[] badCharsTable = new bool[maxChar + 1];
Array.ForEach(badChars, ch => badCharsTable[ch] = true);
and replace badChars.Contains(...) with (ch < badCharsTable.Length && badCharsTable[ch]).
Edit: Finally had time to improve the answer.

ReverseString, a C# interview-question

I had an interview question that asked me for my 'feedback' on a piece of code a junior programmer wrote. They hinted there may be a problem and said it will be used heavily on large strings.
public string ReverseString(string sz)
{
string result = string.Empty;
for(int i = sz.Length-1; i>=0; i--)
{
result += sz[i]
}
return result;
}
I couldn't spot it. I saw no problems whatsoever.
In hindsight I could have said the user should resize but it looks like C# doesn't have a resize (i am a C++ guy).
I ended up writing things like use an iterator if its possible, [x] in containers could not be random access so it may be slow. and misc things. But I definitely said I never had to optimize C# code so my thinking may have not failed me on the interview.
I wanted to know, what is the problem with this code, do you guys see it?
-edit-
I changed this into a wiki because there can be several right answers.
Also i am so glad i explicitly said i never had to optimize a C# program and mentioned the misc other things. Oops. I always thought C# didnt have any performance problems with these type of things. oops.
Most importantly? That will suck performance wise - it has to create lots of strings (one per character). The simplest way is something like:
public static string Reverse(string sz) // ideal for an extension method
{
if (string.IsNullOrEmpty(sz) || sz.Length == 1) return sz;
char[] chars = sz.ToCharArray();
Array.Reverse(chars);
return new string(chars);
}
The problem is that string concatenations are expensive to do as strings are immutable in C#. The example given will create a new string one character longer each iteration which is very inefficient. To avoid this you should use the StringBuilder class instead like so:
public string ReverseString(string sz)
{
var builder = new StringBuilder(sz.Length);
for(int i = sz.Length-1; i>=0; i--)
{
builder.Append(sz[i]);
}
return builder.ToString();
}
The StringBuilder is written specifically for scenarios like this as it gives you the ability to concatenate strings without the drawback of excessive memory allocation.
You will notice I have provided the StringBuilder with an initial capacity which you don't often see. As you know the length of the result to begin with, this removes needless memory allocations.
What normally happens is it allocates an amount of memory to the StringBuilder (default 16 characters). Once the contents attempts to exceed that capacity it doubles (I think) its own capactity and carries on. This is much better than allocating memory each time as would happen with normal strings, but if you can avoid this as well it's even better.
A few comments on the answers given so far:
Every single one of them (so far!) will fail on surrogate pairs and combining characters. Oh the joys of Unicode. Reversing a string isn't the same as reversing a sequence of chars.
I like Marc's optimisation for null, empty, and single character inputs. In particular, not only does this get the right answer quickly, but it also handles null (which none of the other answers do)
I originally thought that ToCharArray followed by Array.Reverse would be the fastest, but it does create one "garbage" copy.
The StringBuilder solution creates a single string (not char array) and manipulates that until you call ToString. There's no extra copying involved... but there's a lot more work maintaining lengths etc.
Which is the more efficient solution? Well, I'd have to benchmark it to have any idea at all - but even so that's not going to tell the whole story. Are you using this in a situation with high memory pressure, where extra garbage is a real pain? How fast is your memory vs your CPU, etc?
As ever, readability is usually king - and it doesn't get much better than Marc's answer on that front. In particular, there's no room for an off-by-one error, whereas I'd have to actually put some thought into validating the other answers. I don't like thinking. It hurts my brain, so I try not to do it very often. Using the built-in Array.Reverse sounds much better to me. (Okay, so it still fails on surrogates etc, but hey...)
Since strings are immutable, each += statement will create a new string by copying the string in the last step, along with the single character to form a new string. Effectively, this will be an O(n2) algorithm instead of O(n).
A faster way would be (O(n)):
// pseudocode:
static string ReverseString(string input) {
char[] buf = new char[input.Length];
for(int i = 0; i < buf.Length; ++i)
buf[i] = input[input.Length - i - 1];
return new string(buf);
}
You can do this in .NET 3.5 instead:
public static string Reverse(this string s)
{
return new String((s.ToCharArray().Reverse()).ToArray());
}
Better way to tackle it would be to use a StringBuilder, since it is not immutable you won't get the terrible object generation behavior that you would get above. In .net all strings are immutable, which means that the += operator there will create a new object each time it is hit. StringBuilder uses an internal buffer, so the reversal could be done in the buffer w/ no extra object allocations.
You should use the StringBuilder class to create your resulting string. A string is immutable so when you append a string in each interation of the loop, a new string has to be created, which isn't very efficient.
I prefer something like this:
using System;
using System.Text;
namespace SpringTest3
{
static class Extentions
{
static private StringBuilder ReverseStringImpl(string s, int pos, StringBuilder sb)
{
return (s.Length <= --pos || pos < 0) ? sb : ReverseStringImpl(s, pos, sb.Append(s[pos]));
}
static public string Reverse(this string s)
{
return ReverseStringImpl(s, s.Length, new StringBuilder()).ToString();
}
}
class Program
{
static void Main(string[] args)
{
Console.WriteLine("abc".Reverse());
}
}
}
x is the string to reverse.
Stack<char> stack = new Stack<char>(x);
string s = new string(stack.ToArray());
This method cuts the number of iterations in half. Rather than starting from the end, it starts from the beginning and swaps characters until it hits center. Had to convert the string to a char array because the indexer on a string has no setter.
public string Reverse(String value)
{
if (String.IsNullOrEmpty(value)) throw new ArgumentNullException("value");
char[] array = value.ToCharArray();
for (int i = 0; i < value.Length / 2; i++)
{
char temp = array[i];
array[i] = array[(array.Length - 1) - i];
array[(array.Length - 1) - i] = temp;
}
return new string(array);
}
Necromancing.
As a public service, this is how you actually CORRECTLY reverse a string (reversing a string is NOT equal to reversing a sequence of chars)
public static class Test
{
private static System.Collections.Generic.List<string> GraphemeClusters(string s)
{
System.Collections.Generic.List<string> ls = new System.Collections.Generic.List<string>();
System.Globalization.TextElementEnumerator enumerator = System.Globalization.StringInfo.GetTextElementEnumerator(s);
while (enumerator.MoveNext())
{
ls.Add((string)enumerator.Current);
}
return ls;
}
// this
private static string ReverseGraphemeClusters(string s)
{
if(string.IsNullOrEmpty(s) || s.Length == 1)
return s;
System.Collections.Generic.List<string> ls = GraphemeClusters(s);
ls.Reverse();
return string.Join("", ls.ToArray());
}
public static void TestMe()
{
string s = "Les Mise\u0301rables";
// s = "noël";
string r = ReverseGraphemeClusters(s);
// This would be wrong:
// char[] a = s.ToCharArray();
// System.Array.Reverse(a);
// string r = new string(a);
System.Console.WriteLine(r);
}
}
See:
https://vimeo.com/7403673
By the way, in Golang, the correct way is this:
package main
import (
"unicode"
"regexp"
)
func main() {
str := "\u0308" + "a\u0308" + "o\u0308" + "u\u0308"
println("u\u0308" + "o\u0308" + "a\u0308" + "\u0308" == ReverseGrapheme(str))
println("u\u0308" + "o\u0308" + "a\u0308" + "\u0308" == ReverseGrapheme2(str))
}
func ReverseGrapheme(str string) string {
buf := []rune("")
checked := false
index := 0
ret := ""
for _, c := range str {
if !unicode.Is(unicode.M, c) {
if len(buf) > 0 {
ret = string(buf) + ret
}
buf = buf[:0]
buf = append(buf, c)
if checked == false {
checked = true
}
} else if checked == false {
ret = string(append([]rune(""), c)) + ret
} else {
buf = append(buf, c)
}
index += 1
}
return string(buf) + ret
}
func ReverseGrapheme2(str string) string {
re := regexp.MustCompile("\\PM\\pM*|.")
slice := re.FindAllString(str, -1)
length := len(slice)
ret := ""
for i := 0; i < length; i += 1 {
ret += slice[length-1-i]
}
return ret
}
And the incorrect way is this (ToCharArray.Reverse):
func Reverse(s string) string {
runes := []rune(s)
for i, j := 0, len(runes)-1; i < j; i, j = i+1, j-1 {
runes[i], runes[j] = runes[j], runes[i]
}
return string(runes)
}
Note that you need to know the difference between
- a character and a glyph
- a byte (8 bit) and a codepoint/rune (32 bit)
- a codepoint and a GraphemeCluster [32+ bit] (aka Grapheme/Glyph)
Reference:
Character is an overloaded term than can mean many things.
A code point is the atomic unit of information. Text is a sequence of
code points. Each code point is a number which is given meaning by the
Unicode standard.
A grapheme is a sequence of one or more code points that are displayed
as a single, graphical unit that a reader recognizes as a single
element of the writing system. For example, both a and ä are
graphemes, but they may consist of multiple code points (e.g. ä may be
two code points, one for the base character a followed by one for the
diaresis; but there's also an alternative, legacy, single code point
representing this grapheme). Some code points are never part of any
grapheme (e.g. the zero-width non-joiner, or directional overrides).
A glyph is an image, usually stored in a font (which is a collection
of glyphs), used to represent graphemes or parts thereof. Fonts may
compose multiple glyphs into a single representation, for example, if
the above ä is a single code point, a font may chose to render that as
two separate, spatially overlaid glyphs. For OTF, the font's GSUB and
GPOS tables contain substitution and positioning information to make
this work. A font may contain multiple alternative glyphs for the same
grapheme, too.
static string reverseString(string text)
{
Char[] a = text.ToCharArray();
string b = "";
for (int q = a.Count() - 1; q >= 0; q--)
{
b = b + a[q].ToString();
}
return b;
}

Categories

Resources