Index of the string can be long? - c#

I want to know whether we can give the index of the string as Long data type.
var i=long.Parse(Console.ReadLine());
var result = testString[i-1];
the second line giving me the error by saying that "The best overloaded method match for 'string.this[int]' has some invalid arguments."

No you can't use long for most collection types (you haven't specified what testString is).
One way to get around this would be to segregate the string into a multi-part / multi-dimension array then use a multiplier to get which part of the array to check.
For example:
Your index is 100,000 and you have an array of shorts (32,767 length)...
string[,] testString = new string[100, 32766]; //Replace this with your Initialisation / existing string
var arrayRank = (int)Math.Round((double) 100000 / 32767, 0);
var arrayIndex = (int)Math.Round((double)100000 % 32767, 0);
//Test this works.
//testString[arrayRank, arrayIndex] = "test"; - Test to see that the array range is assignable.
var result = testString[arrayRank, arrayIndex]; //Test value is what we expect
This may not be the most efficient way to go about things, but it is a workaround.

No, it cannot accept a long. The only overload accepts an int indexer. You would need to change your code to int.Parse() instead of long.Parse()

There is no way to pass long as an index of array, compiler doesn't allow that.
Workaround can be converting the long to int, this is called narrow conversion.
var result= testString[(int)i)];

Related

How to extract a fragment of an element in an existing array to generate a new array

I have an array :
string[] arr = new string[2]
arr[0] = "a=01"
arr[1] = "b=02"
How can I take those number out and make a new array to store them? What I am expecting is :
int [] newArr = new int[2]
Inside newArr, there are 2 elements, one is '01' and the other one is '02' which both from arr.
Another way besides Substring to get the desired result is to use String.Split on the = character. This is assuming the string will always have the format of letters and numbers, separated by a =, with no other = characters in the input string.
for (var i = 0; i < arr.Length; i++)
{
// Split the array item on the `=` character.
// This results in an array of two items ("a" and "01" for the first item)
var tmp = arr[i].Split('=');
// If there are fewer than 2 items in the array, there was not a =
// character to split on, so continue to the next item.
if (tmp.Length < 2)
{
continue;
}
// Try to parse the second item in the tmp array (which is the number
// in the provided example input) as an Int32.
int num;
if (Int32.TryParse(tmp[1], out num))
{
// If the parse is succesful, assign the int to the corresponding
// index of the new array.
newArr[i] = num;
}
}
This can be shortened in a lambda expression like the other answer like so:
var newArr = arr.Select(x => Int32.Parse(x.Split('=')[1])).ToArray();
Though doing it with Int32.Parse can result in an exception if the provided string is not an integer. This also assumes that there is a = character, with only numbers to the right of it.
Take a substring and then parse as int.
var newArr = arr.Select(x=>Int32.Parse(x.Substring(2))).ToArray();
As other answers have noted, it's quite compact to use linq. PM100 wrote:
var newArr = arr.Select(x=>Int32.Parse(x.Substring(2))).ToArray();
You asked what x was.. that linq statement there is conceptually the equivalent of something like:
List<int> nums = new List<int>();
foreach(string x in arr)
nums.Add(Int32.Parse(x.Substring(2);
var newArr = nums.ToArray();
It's not exactly the same, internally linq probably doesn't use a List, but it embodies the same concept - for each element (called x) in the string array, cut the start off it, parse the result as an int, add it to a collection, convert the collection to an array
Sometimes I think linq is overused; here probably efficiencies could be gained by directly declaring an int array the size of the string one and filling it directly, rather than adding to a List or other collection, that is later turned into an int array. Proponents of either style could easily be found; linq is compact and makes relatively trivial work of more long hand constructs such as loops within loops within loops. Though not necessarily easy to work out for those unfamiliar with how to read it it does bring a certain self documenting aspect to code because it uses English words like Any, Where, Distinct and these more quickly convey a concept than does looking at a loop code that exits early when a test returns true (Any) or builds a dictionary/hashset from all elements and returns it (Distinct)

In C#, is it possible to pass objects that are supposed to be formatted by String's format method as an array?

If I have a string, say, "[{0:000}{1:00000}]" then it is possble to do some formatting like this in C#: String.Format("[{0:000}{1:00000}]", 2, 3);
Let us assume that I have a list (or an array) of integers:
List<int> intList = new List<int>();
intList.Add(2);
intList.Add(3);
Is it somehow possible to pass that list to String's format method so that formattings will be carried out in the way that the ints' index corresponds to the format-string's index ({0:..., {1:..., that is)? I have strong doubts on the feasibility of this, but I would be very beholden to any inventive mind proving that it can actually be done.
string.Format accepts single objects or arrays of objects as parameters. Your argument has to match the method signature.
var result = string.Format("[{0:000}{1:00000}]", intList.Cast<object>().ToArray());
Passing your list as an array of objects does exactly that.
From the method String.Format(String, Object[]) documentation:
This method will :
Replaces the format item in a specified string with the string representation of a corresponding object in a specified array.
Like :
var foo = new List<int>{1,2,3,4,5,6,7,8};
Console.WriteLine("{0}, {3}, {2}, {1}, {4}", foo.Cast<object>().ToArray());
https://dotnetfiddle.net/ZLiNji
The indice will be those of the array but take care that:
Index (zero based) must be greater than or equal to zero and less than the size of the argument list

How to get the length of an array with out empty value?

I'm now doing a project about solving a Magic cube problem. I want to create an array to remember the steps like this:
char[] Steps = new char[200];
Each time I do the 'F','B','R','L','U','D' turn method, it will add a 'F','B','R','L','U','D' character in the array.
But when I want to get the length of the steps, it always shows 200.
for example:
char[] steps = new char[5];
and now I've already added 3 steps:
steps[] = {'f','b','f','',''};
How can I get the length '3'?
Or is there any alternative method I can use that I don't need to set the length at the beginning?
you can just use List<char> but if performance is really critical in your sceanario you can just initialize the initial capacity
something like the following
List<char> list = new List<char>(200);
list.Add('c');
list.Add('b');
here count will return just what you have really added
var c = list.Count;
note in list you can apply Linq Count() or just use the Count property which does not need to compute like Linq and return the result immediately
You will get compilation error on this line
steps[] = {'f','b','f','',''};
As you cannot use empty char and you need to write steps instead of steps[].
I will suggest you to use string array instead and using LINQ get count of not empty elements in this way:
string [] steps = {"f","b","f","",""};
Console.WriteLine(steps.Where(x=>!string.IsNullOrEmpty(x)).Count());
To count non-empty items using System.Linq:
steps.Count(x => x != '\0');
Your code doesn't compile since '' isn't allowed as a char, but I'm assuming that you mean empty elements in a char array which are actually represented by '\0' or the Unicode Null. So the above condition simply counts the non null items in your array.
you could use a list of character that would make things a lot simpler like this :
List<char> steps = new List<char>();
and just add a line to the list for each steps :
char move = 'F';
steps.add(move);
finally then you can count the number of move in the list easily
int numberofmove = steps.count();

Why does the string Remove() method allow a char as a parameter?

Consider this code:
var x = "tesx".Remove('x');
If I run this code, I get this exception:
startIndex must be less than length of string.
Why can I pass a char instead of an int to this method?
Why don't I get a compilation error?
Why does the compiler have this behavior?
you try to remove 'x' which is a declared as char, x is equal to 120
The .Remove only takes 2 parameters of type int the start and (optional) count to remove from the string.
If you pass a char, it will be converted to the integer representation. Meaning if you pass 'x' -> 120 is greater than the string's .Length and that's why it will throw this error!
Implicit conversion lets you compile this code since char can be converted to int and no explicit conversion is required. This will also compile and the answer will be 600 (120*5) -
char c = 'x';
int i = c;
int j = 5;
int answer = i * j;
From MSDN, implicit conversion is summarized as below -
As other's have stated you could use Replace or Remove with valid inputs.
There is no overload of Remove that takes a char, so the character is implicitly converted to an int and the Remove method tries to use it as an index into the string, which is way outside the string. That's why you get that runtime error instead of a compile time error saying that the parameter type is wrong.
To use Remove to remove part of a string, you first need to find where in the string that part is. Example:
var x = "tesx";
var x = x.Remove(x.IndexOf('x'), 1);
This will remove the first occurance of 'x' in the string. If there could be more than one occurance, and you want to remove all, using Replace is more efficient:
var x = "tesx".Replace("x", String.Empty);
Remove takes an int parameter for the index within the string to start removing characters, see msdn. The remove call must automatically convert the char to its ASCII integer index and try to remove the character at that index from the string, it is not trying to remove the character itself.
If you just want to remove any cases where x occurs in the string do:
"testx".Replace("x",string.Empty);
If you want to remove the first index of x in the string do:
var value = "testx1x2";
var newValue = value.Remove(value.IndexOf('x'), 1);
Since you are passing a char in the function and this value is getting converted to int at runtime hence you are getting the runtime error because the value of char at runtime is more than the length of the string.You may try like this:-
var x = "tesx";
var s = x.Remove(x.IndexOf('x'), 1);
or
var s = x.Replace("x",string.Empty);
.Remove takes the int as parameter. Remove takes two parameters. The first one is what position in your string you want to start at. (The count starts at zero.) The second parameter is how many characters you want to delete, starting from the position you specified.
On a side note:
From MSDN:
This method(.Remove) does not modify the value of the current instance.
Instead, it returns a new string in which the number of characters
specified by the count parameter have been removed. The characters are
removed at the position specified by startIndex.
You can use extension methods to create your own methods for already existing classes. Consider following example:
using System;
using MyExtensions;
namespace ConsoleApplication
{
class Program
{
static void Main(string[] args)
{
const string str1 = "tesx";
var x = str1.RemoveByChar('x');
Console.WriteLine(x);
Console.ReadKey();
}
}
}
namespace MyExtensions
{
public static class StringExtensions
{
public static string RemoveByChar(this String str, char c)
{
return str.Remove(str.IndexOf(c), 1);
}
}
}

c# - BinarySearch StringList with wildcard

I have a sorted StringList and wanted to replace
foreach (string line3 in CardBase.cardList)
if (line3.ToLower().IndexOf((cardName + Config.EditionShortToLong(edition)).ToLower()) >= 0)
{
return true;
}
with a binarySearch, since the cardList ist rather large(~18k) and this search takes up around 80% of the time.
So I found the List.BinarySearch-Methode, but my problem is that the lines in the cardList look like this:
Brindle_Boar_(Magic_2012).c1p247924.prod
But I have no way to generate the c1p... , which is a problem cause the List.BinarySearch only finds exact matches.
How do I modify List.BinarySearch so that it finds a match if only a part of the string matches?
e. g.
searching for Brindle_Boar_(Magic_2012) should return the position of Brindle_Boar_(Magic_2012).c1p247924.prod
List.BinarySearch will return the ones complement of the index of the next item larger than the request if an exact match is not found.
So, you can do it like this (assuming you'll never get an exact match):
var key = (cardName + Config.EditionShortToLong(edition)).ToLower();
var list = CardBase.cardList;
var index = ~list.BinarySearch(key);
return index != list.Count && list[index].StartsWith(key);
BinarySearch() has an overload that takes an IComparer<T> has second parameter, implement a custom comparer and return 0 when you have a match within the string - you can use the same IndexOf() method there.
Edit:
Does a binary search make sense in your scenario? How do you determine that a certain item is "less" or "greater" than another item? Right now you only provide what would constitute a match. Only if you can answer this question, binary search applies in the first place.
You can take a look at the C5 Generic Collection Library (you can install it via NuGet also).
Use the SortedArray(T) type for your collection. It provides a handful of methods that could prove useful. You can even query for ranges of items very efficiently.
var data = new SortedArray<string>();
// query for first string greater than "Brindle_Boar_(Magic_2012)" an check if it starts
// with "Brindle_Boar_(Magic_2012)"
var a = data.RangeFrom("Brindle_Boar_(Magic_2012)").FirstOrDefault();
return a.StartsWith("Brindle_Boar_(Magic_2012)");
// query for first 5 items that start with "Brindle_Boar"
var b = data.RangeFrom("string").Take(5).Where(s => s.StartsWith("Brindle_Boar"));
// query for all items that start with "Brindle_Boar" (provided only ascii chars)
var c = data.RangeFromTo("Brindle_Boar", "Brindle_Boar~").ToList()
// query for all items that start with "Brindle_Boar", iterates until first non-match
var d = data.RangeFrom("Brindle_Boar").TakeWhile(s => s.StartsWith("Brindle_Boar"));
The RageFrom... methods perform a binary search, find the first element greater than or equal to your argument, that returns an iterator from that position

Categories