Can I assign each value in an array to separate variables in one line in C#? Here's an example in Ruby code of what I want:
irb(main):001:0> str1, str2 = ["hey", "now"]
=> ["hey", "now"]
irb(main):002:0> str1
=> "hey"
irb(main):003:0> str2
=> "now"
I'm not sure if what I'm wanting is possible in C#.
Edit: for those suggesting I just assign the strings "hey" and "now" to variables, that's not what I want. Imagine the following:
irb(main):004:0> val1, val2 = get_two_values()
=> ["hey", "now"]
irb(main):005:0> val1
=> "hey"
irb(main):006:0> val2
=> "now"
Now the fact that the method get_two_values returned strings "hey" and "now" is arbitrary. In fact it could return any two values, they don't even have to be strings.
This is not possible in C#.
The closest thing I can think of is to use initialization in the same line with indexs
strArr = new string[]{"foo","bar"};
string str1 = strArr[0], str2 = strArr[1];
Update: In C#7 you can easily assign multiple variables at once using tuples. In order to assign array elements to variables, you'd need to write an appropriate Deconstruct() extension methods:
Another way to consume tuples is to deconstruct them. A deconstructing
declaration is a syntax for splitting a tuple (or other value) into
its parts and assigning those parts individually to fresh variables:
(string first, string middle, string last) = LookupName(id1); // deconstructing declaration
WriteLine($"found {first} {last}.");
In a deconstructing declaration you can use var for the individual
variables declared:
(var first, var middle, var last) = LookupName(id1); // var inside
Or even put a single var outside of the parentheses as an
abbreviation:
var (first, middle, last) = LookupName(id1); // var outside
You can also deconstruct into existing variables with a deconstructing
assignment:
(first, middle, last) = LookupName(id2); // deconstructing assignment
Deconstruction is not just for tuples. Any type can be deconstructed,
as long as it has an (instance or extension) deconstructor method of
the form:
public void Deconstruct(out T1 x1, ..., out Tn xn) { ... }
The out parameters constitute the values that result from the
deconstruction.
(Why does it use out parameters instead of returning a tuple? That is
so that you can have multiple overloads for different numbers of
values).
class Point
{
public int X { get; }
public int Y { get; }
public Point(int x, int y) { X = x; Y = y; }
public void Deconstruct(out int x, out int y) { x = X; y = Y; }
}
(var myX, var myY) = GetPoint(); // calls Deconstruct(out myX, out myY);
It will be a common pattern to have constructors and deconstructors be
“symmetric” in this way.
https://blogs.msdn.microsoft.com/dotnet/2016/08/24/whats-new-in-csharp-7-0/
Old answer:
In fact, you can achieve similar functionality in C# by using extension methods like this (note: I haven't include checking if arguments are valid):
public static void Match<T>(this IList<T> collection, Action<T,T> block)
{
block(collection[0], collection[1]);
}
public static void Match<T>(this IList<T> collection, Action<T,T,T> block)
{
block(collection[0], collection[1], collection[2]);
}
//...
And you can use them like this:
new[] { "hey", "now" }.Match((str1, str2) =>
{
Console.WriteLine(str1);
Console.WriteLine(str2);
});
In case a return value from a function is needed, the following overload would work:
public static R Match<T,R>(this IList<T> collection, Func<T, T, R> block)
{
return block(collection[0], collection[1]);
}
private string NewMethod1()
{
return new[] { "hey", "now" }.Match((str1, str2) =>
{
return str1 + str2;
});
}
In this way:
You avoid having to repeat array name like in solution proposed by JaredPar and others; the list of "variables" is easy to read.
You avoid having to explicitly declare variables types like in Daniel Earwicker's solution.
The disadvantage is that you end up with additional code block, but I think it's worth it. You can use code snippets in order to avoid typing braces etc. manually.
I know it's a 7 years old question, but not so long time ago I needed such a solution - easy giving names to array elements passed into the method (no, using classes/structs instead of arrays wasn't practical, because for same arrays I could need different element names in different methods) and unfortunately I ended up with code like this:
var A = points[0];
var A2 = points[1];
var B = points[2];
var C2 = points[3];
var C = points[4];
Now I could write (in fact, I've refactored one of those methods right now!):
points.Match((A, A2, B, C2, C) => {...});
My solution is similar to pattern matching in F# and I was inspired by this answer: https://stackoverflow.com/a/2321922/6659843
The real-world use case for this is providing a convenient way to return multiple values from a function. So it is a Ruby function that returns a fixed number of values in the array, and the caller wants them in two separate variables. This is where the feature makes most sense:
first_name, last_name = get_info() // always returns an array of length 2
To express this in C# you would mark the two parameters with out in the method definition, and return void:
public static void GetInfo(out string firstName, out string lastName)
{
// assign to firstName and lastName, instead of trying to return them.
}
And so to call it:
string firstName, lastName;
SomeClass.GetInfo(out firstName, out lastName);
It's not so nice. Hopefully some future version of C# will allow this:
var firstName, lastName = SomeClass.GetInfo();
To enable this, the GetInfo method would return a Tuple<string, string>. This would be a non-breaking change to the language as the current legal uses of var are very restrictive so there is no valid use yet for the above "multiple declaration" syntax.
You can do it in one line, but not as one statement.
For example:
int str1 = "hey"; int str2 = "now";
Python and ruby support the assignment you're trying to do; C# does not.
You can do this in C#
string str1 = "hey", str2 = "now";
or you can be fancy like this
int x, y;
int[] arr = new int[] { x = 1, y = 2 };
You can use named tuples with C# 7 now.
{
(string part1, string part2) = Deconstruct(new string[]{"hey","now"});
}
public (string, string) Deconstruct(string[] parts)
{
return (parts[0], parts[1]);
}
I'm not sure if what I'm wanting is
possible in C#.
It's not.
No, but you can initialize an array of strings:
string[] strings = new string[] {"hey", "now"};
Although that's probably not too useful for you. Frankly its not hard to put them on two lines:
string str1 = "hey";
string str2 = "now";
Related
So, I'm pretty new to C# and I'm trying to order an Array using a custom Comparer.
I created a class:
class MySorter : IComparer
{
public int Compare(object x, object y)
{
var chars = "jngmclqskrzfvbwpxdht";
if (chars.IndexOf((char)x) < chars.IndexOf((char)y))
return -1;
return chars.IndexOf((char)x) > chars.IndexOf((char)y) ? 1 : 0;
}
}
And I have a Array full of words.
How exacly I can use this Compare to sort?
I think that what you need is this. Declare a method for sorting as you already did.
public static int CompareStrings(string s1, string s2)
{
// TODO: your code here
}
... and specify what function you need to use.
string[] myStrings = { ... };
Array.Sort(myStrings, CompareStrings);
If you use generic classes, you can achieve this as well doing as it follows:
List<string> myStrings = ...;
myStrings.Sort(CompareStrings);
To answer this question for people wishing to use Linq the solution would be:
IEnumerable<string> words = new [] {"foo", "bar"};
words = words.OrderBy(x => x, new MySorter());
Note therefore that you should be using the generic interface for your comparer:
class MySorter : IComparer<string>
{
public int Compare(string x, string y)
{
}
}
You can then use Linq to sort even objects:
IEnumerable<Person> people = new []
{
new Person
{
Name = "Matthew"
},
new Person
{
Name = "Mark"
}
};
people = people.OrderBy(x => x.Name, new MySorter());
An important note relating to some of the issues you highlighted under Simply Me's answer:
Using the generic interface is always preferable when the types being compared are known, as amongst other things this would have alerted you at compile time rather than run time (when you got an InvalidCastException) that if you are sorting an array of words, assuming a word is a string, the IComparer you are implementing is not fit for purpose as it is comparing two char types.
(From what I am inferring by looking at your code, I think what you need to do is implement IComparer<string> and in the Compare method iterate through each char of both strings until they differ, and then use your char comparison logic - but, you should also consider how you handle uppercase and lowercase, what you do when one or both characters are not in your list and if one string in its entirety matches the first part of the other string, such as match and matches.)
I have two string arrays, newArray and oldArray, and I want to use Enumberable.Except method to remove all items that are in newArray that are also in oldArray and then write the result to a csv file.
However, I need to use a custom comparer in order to check for formatting similarities(if there is a new line character in one array and not the other, I don't want this item being written to the file).
My code as of now:
string newString = File.ReadAllText(csvOutputFile1);
string[] newArray = newString.Split(new string[] {sentinel}, StringSplitOptions.RemoveEmptyEntries);
string oldString = File.ReadAllText(csvOutputFile2);
string[] oldArray = oldString.Split(new string[] { sentinel }, StringSplitOptions.None);
IEnumerable<string> differnceQuery = newArray.Except(oldArray, new Comparer());
using (var wtr = new StreamWriter(diffFile))
{
foreach (var s in differnceQuery)
{
wtr.WriteLine(s.Trim() + "#!#");
}
}
and the custom comparer class:
class Comparer : IEqualityComparer<string>
{
public bool Equals(string x, string y)
{
x = x.ToString().Replace(" ", "").Replace("\n", "").Replace("\r", "");
y = y.ToString().Replace(" ", "").Replace("\n", "").Replace("\r", "");
if (x == y)
return true;
else
return false;
}
public int GetHashCode(string row)
{
int hCode = row.GetHashCode();
return hCode;
}
}
The resulting file is not omitting the formatting difference items between the two arrays. So although it catches items that are in the newArray but not in the oldArray(like it should), it is also putting in items that are only different because of a \n or something even though in my custom comparer I am removing them.
The thing I really don't understand is when I debug and step through my code, I can see each pair of items being analyzed in my custom comparer class, but only when they are equal terms. If for example the string "This is\nthe 1st term" is in newArray and the string "This is the first array" is in oldArray, the debugger doesn't even enter the comparer class and instead jumps straight to the writeline part of my code in the main class.
simply: your hash-code does not correctly mirror your equality method. Strings like "a b c" and "abc" would return different values from GetHashCode, so it would never get around to testing Equals. GetHashCode must return the same result for any two values that could be equal. It is not, however, necessary that two strings that are not equal return different hash-codes (although it is highly desirable, otherwise everything will go into the same hash-bucket).
I guess you could use:
// warning: probably not very efficient
return x.Replace(" ", "").Replace("\n", "").Replace("\r", "").GetHashCode();
but that looks pretty expensive (lots of potential for garbage strings to be generated all the time)
I am trying to find the differences in two lists. List, "y" should have 1 unique value when compared to list "x". However, Except, does not return the difference. The, "differences" list's count always equals 0.
List<EtaNotificationUser> etaNotifications = GetAllNotificationsByCompanyIDAndUserID(PrevSelectedCompany.cmp_ID);
IEnumerable<string> x = etaNotifications.OfType<string>();
IEnumerable<string> y = EmailList.OfType<string>();
IEnumerable<string> differences = x.Except(y, new StringLengthEqualityComparer()).ToList();
foreach(string diff in differences)
{
addDiffs.Add(diff);
}
After reading a few posts and articles on the post, I created a custom comparer. The comparer looks at string length (kept it simple for testing) and obtains the Hashcode, since these are two objects of a different type (even though I convert their types to string), I thought it may have been the issue.
class StringLengthEqualityComparer : IEqualityComparer<string>
{
public bool Equals(string x, string y)
{
return x.Length == y.Length;
}
public int GetHashCode(string obj)
{
return obj.Length;
}
}
This is my first time using Except. Sounds like a great, optimized way of comparing two lists, but I can't get it to work.
Update
X - Should hold Email Addresses from the database.
GetAllNotificationsByCompanyIDAndUserID - brings back email values from the DB.
Y - Should hold all Email Addresses in the UI Grid.
What I am trying to do is detect if a new e-mail has been added to the grid. So at this point X will have the saved values from past entries. Y will have any new e-mail addresses add by the user and have not been saved yet.
I have verified this is all working correctly.
The problem is here:
IEnumerable<string> x = etaNotifications.OfType<string>();
but etaNotifications is a List<EtaNotificationUser>, none of which can be a string since string is sealed. OfType returns all instances that are of the given type - it does not "convert" each member to that type.
So x will always be empty.
Maybe you want:
IEnumerable<string> x = etaNotifications.Select(e => e.ToString());
if EtaNotificationUser has overridden ToString to give you the value you want to compare. If the value you want to compare is in a property you can use:
IEnumerable<string> x = etaNotifications.Select(e => e.EmailAddress);
or some other property.
You'll likely have to do something similar for y (unless EmailList is already a List<string> which I doubt).
Assuming you have verified that your two enumerables x and y actually contain the strings you expect them to, I believe your problem is with your string comparer. According to the docs, Enumerable.Except "Produces the set difference of two sequences. The set difference is the members of the first sequence that don't appear in the second sequence." But your equality comparer equates all strings with the same length. Thus, if a string in the first sequence happens to have the same length as a string in the second, it will not be found as different using your comparer.
Update: yup, I just tested it:
public class StringLengthEqualityComparer : IEqualityComparer<string>
{
public bool Equals(string x, string y)
{
return x.Length == y.Length;
}
public int GetHashCode(string obj)
{
return obj.Length;
}
}
string [] array1 = new string [] { "foo", "bar", "yup" };
string[] array2 = new string[] { "dll" };
int diffCount;
diffCount = 0;
foreach (var diff in array1.Except(array2, new StringLengthEqualityComparer()))
{
diffCount++;
}
Debug.Assert(diffCount == 0); // No assert.
diffCount = 0;
foreach (var diff in array1.Except(array2))
{
diffCount++;
}
Debug.Assert(diffCount == 0); // Assert b/c diffCount == 3.
There is no assert with the custom comparer but there is with the standard.
I'm coming from a C++ background. This question has been asked before, but try as I might I cannot find the answer. Let's say I have:
string[] ArrayOfReallyVeryLongStringNames = new string[500];
ArrayOfReallyVeryLongStringNames[439] = "Hello world!";
Can I create a string that references the above (neither of these will compile):
string a = ref ArrayOfReallyVeryLongStringNames[439]; // no compile
string a = &ArrayOfReallyVeryLongStringNames[439]; // no compile
I do understand that strings are immutable in C#. I also understand that you cannot get the address of a managed object.
I'd like to do this:
a = "Donkey Kong"; // Now ArrayOfReallyVeryLongStringNames[439] = "Donkey Kong";
I have read the Stack Overflow question Make a reference to another string in C#
which has an excellent answer, but to a slightly different question. I do NOT want to pass this parameter to a function by reference. I know how to use the "ref" keyword for passing a parameter by reference.
If the answer is "You cannot do this in C#", is there a convenient workaround?
EDIT:
Some of the answers indicate the question was unclear. Lets ask it in a different way. Say I needed to manipulate all items in the original long-named array that have prime indices. I'd like to add aliases to Array...[2], Array...[3], Array...[5], etc to a list. Then, modify the items in the list using a "for" loop (perhaps by passing the list just created to a function).
In C# the "using" keyword creates an alias to a class or namespace. It seems from the answers, that it is not possible to create an alias to a variable, however.
You could create a wrapper that keeps a reference to the underlying array AND the index of the string:
public sealed class ArrayStringReference
{
private readonly string[] _array;
private readonly int _index;
public ArrayStringReference(string[] array, int index)
{
_array = array;
_index = index;
}
public string Value
{
get
{
return _array[_index];
}
set
{
_array[_index] = value;
}
}
public override string ToString()
{
return Value;
}
}
Then this will work:
string[] ArrayOfReallyVeryLongStringNames = new string[500];
ArrayOfReallyVeryLongStringNames[439] = "Hello world!";
var strRef = new ArrayStringReference(ArrayOfReallyVeryLongStringNames, 439);
Console.WriteLine(ArrayOfReallyVeryLongStringNames[439]); // Outputs "Hello world!"
strRef.Value = "Donkey Kong";
Console.WriteLine(ArrayOfReallyVeryLongStringNames[439]); // Outputs "Donkey Kong"
You could make this more convenient to use by providing an implicit string operator so you don't have to use .Value to access the underlying string:
// Add this to class ArrayStringReference implementation
public static implicit operator string(ArrayStringReference strRef)
{
return strRef.Value;
}
Then instead of having to access the underlying string like this:
strRef.Value = "Donkey Kong";
...
string someString = strRef.Value;
You can do this:
strRef.Value = "Donkey Kong";
...
string someString = strRef; // Don't need .Value
This is just syntactic sugar, but it might make it easier to start using an ArrayStringReference in existing code. (Note that you will still need to use .Value to set the underlying string.)
The closest you can get is this:
unsafe
{
string* a = &ArrayOfReallyVeryLongStringNames[439]; // no compile
}
Which gives an exception:
Cannot take the address of, get the size of, or declare a pointer to a managed type ('string')
So no, not possible...
Also read this MSDN article which explains what types can be used (blittable types).
When I do something like this in C#:
string a = "String 1";
string b = a;
a = "String 2";
Console.WriteLine(a); // String 2
Console.WriteLine(b); // String 1
The thing is, both "String 1" and "String 2" literals are created at the start of the program, and strings are always pointers: at first a references "String 1" literal and afterwards it references "String 2". If you want them to always reference the same thing, in C# you just use the same variable.
The string objects themselves are immutable in C#:
Because a string "modification" is actually a new string creation, you must use caution when you create references to strings. If you create a reference to a string, and then "modify" the original string, the reference will continue to point to the original object instead of the new object that was created when the string was modified.
When the string mutability is needed, for example, to concatenate a lot of strings faster, other classes are used, like StringBuilder.
To sum it up, what you're trying to do is impossible.
In C#, a String is an Object. Therefore String a = "Donkey Kong" says that a now have a reference to this string that is being allocated over the memory. Then all you need to do is:
ArrayOfReallyVeryLongStringNames[439] = a;
And that will copy the refrence (which you should be thinking of in C#!!!) to the location in the string.
BUT!! When you do a="new string";, a will get a new reference. See the example I made:
http://prntscr.com/3kw18v
You can only do this with unsafe mode.
You could create a wrapper
public class StringWrapper
{
public string Value {get;set;}
}
StringWrapper[] arrayOfWrappers = new StringWrapper[500];
arrayOfWrappers[439] = new StringWrapper { Value = "Hello World" };
StringWrapper a = arrayOfWrappers[439];
a.Value = "New Value";
What you are trying to do is universally discouraged, and actively prevented, in C#, where the logic should be independent of the memory model, however, refer to related SO question C# memory address and variable for some info.
EDIT 1
A more canonical approach to your actual problem in C# would be:
// using System.Linq;
string[] raw = new string[] { "alpha", "beta", "gamma", "delta" };
List<int> evenIndices = Enumerable.Range(0, raw.Length)
.Where(x => x % 2 == 0)
.ToList();
foreach (int x in evenIndices)
raw[x] = raw[x] + " (even)";
foreach (string x in raw)
Console.WriteLine(x);
/*
OUTPUT:
alpha (even)
beta
gamma (even)
delta
*/
If you really want to modify the original memory structure itself, then perhaps C++ is a more appropriate language choice for the solution.
EDIT 2
Looking around on SO, you may want to look at this answer Hidden Features of C#? to an unrelated question.
[TestMethod]
public void TestMethod1()
{
string[] arrayOfString = new string[500];
arrayOfString[499] = "Four Ninty Nine";
Console.WriteLine("Before Modification : {0} " , arrayOfString[499]);
string a = arrayOfString[499];
ModifyString(out arrayOfString[499]);
Console.WriteLine("after a : {0}", a);
Console.WriteLine("after arrayOfString [499]: {0}", arrayOfString[499]);
}
private void ModifyString(out string arrayItem)
{
arrayItem = "Five Hundred less one";
}
Of course you can, hehe:
var a = __makeref(array[666]);
__refvalue(a, string) = "hello";
But you would have to have a very good reason to do it this way.
I need to search a string in the string array. I dont want to use any for looping in it
string [] arr = {"One","Two","Three"};
string theString = "One"
I need to check whether theString variable is present in arr.
Well, something is going to have to look, and looping is more efficient than recursion (since tail-end recursion isn't fully implemented)... so if you just don't want to loop yourself, then either of:
bool has = arr.Contains(var); // .NET 3.5
or
bool has = Array.IndexOf(arr, var) >= 0;
For info: avoid names like var - this is a keyword in C# 3.0.
Every method, mentioned earlier does looping either internally or externally, so it is not really important how to implement it. Here another example of finding all references of target string
string [] arr = {"One","Two","Three"};
var target = "One";
var results = Array.FindAll(arr, s => s.Equals(target));
Does it have to be a string[] ? A List<String> would give you what you need.
List<String> testing = new List<String>();
testing.Add("One");
testing.Add("Two");
testing.Add("Three");
testing.Add("Mouse");
bool inList = testing.Contains("Mouse");
bool exists = arr.Contains("One");
I think it is better to use Array.Exists than Array.FindAll.
Its pretty simple. I always use this code to search string from a string array
string[] stringArray = { "text1", "text2", "text3", "text4" };
string value = "text3";
int pos = Array.IndexOf(stringArray, value);
if (pos > -1)
{
return true;
}
else
{
return false;
}
If the array is sorted, you can use BinarySearch. This is a O(log n) operation, so it is faster as looping. If you need to apply multiple searches and speed is a concern, you could sort it (or a copy) before using it.
Each class implementing IList has a method Contains(Object value). And so does System.Array.
Why the prohibition "I don't want to use any looping"? That's the most obvious solution. When given the chance to be obvious, take it!
Note that calls like arr.Contains(...) are still going to loop, it just won't be you who has written the loop.
Have you considered an alternate representation that's more amenable to searching?
A good Set implementation would perform well. (HashSet, TreeSet or the local equivalent).
If you can be sure that arr is sorted, you could use binary search (which would need to recurse or loop, but not as often as a straight linear search).
You can use Find method of Array type. From .NET 3.5 and higher.
public static T Find<T>(
T[] array,
Predicate<T> match
)
Here is some examples:
// we search an array of strings for a name containing the letter “a”:
static void Main()
{
string[] names = { "Rodney", "Jack", "Jill" };
string match = Array.Find (names, ContainsA);
Console.WriteLine (match); // Jack
}
static bool ContainsA (string name) { return name.Contains ("a"); }
Here’s the same code shortened with an anonymous method:
string[] names = { "Rodney", "Jack", "Jill" };
string match = Array.Find (names, delegate (string name)
{ return name.Contains ("a"); } ); // Jack
A lambda expression shortens it further:
string[] names = { "Rodney", "Jack", "Jill" };
string match = Array.Find (names, n => n.Contains ("a")); // Jack
At first shot, I could come up with something like this (but it's pseudo code and assuming you cannot use any .NET built-in libaries). Might require a bit of tweaking and re-thinking, but should be good enough for a head-start, maybe?
int findString(String var, String[] stringArray, int currentIndex, int stringMaxIndex)
{
if currentIndex > stringMaxIndex
return (-stringMaxIndex-1);
else if var==arr[currentIndex] //or use any string comparison op or function
return 0;
else
return findString(var, stringArray, currentIndex++, stringMaxIndex) + 1 ;
}
//calling code
int index = findString(var, arr, 0, getMaxIndex(arr));
if index == -1 printOnScreen("Not found");
else printOnScreen("Found on index: " + index);
In C#, if you can use an ArrayList, you can use the Contains method, which returns a boolean:
if MyArrayList.Contains("One")
You can check the element existence by
arr.Any(x => x == "One")
it is old one ,but this is the way i do it ,
enter code herevar result = Array.Find(names, element => element == "One");
I'm surprised that no one suggested using Array.IndexOf Method.
Indeed, Array.IndexOf has two advantages :
It allows searching if an element is included into an array,
It gets at the same time the index into the array.
int stringIndex = Array.IndexOf(arr, theString);
if (stringIndex >= 0)
{
// theString has been found
}
Inline version :
if (Array.IndexOf(arr, theString) >= 0)
{
// theString has been found
}
Using Contains()
string [] SomeArray = {"One","Two","Three"};
bool IsExist = SomeArray.Contains("One");
Console.WriteLine("Is string exist: "+ IsExist);
Using Find()
string [] SomeArray = {"One","Two","Three"};
var result = Array.Find(SomeArray, element => element == "One");
Console.WriteLine("Required string is: "+ result);
Another simple & traditional way, very useful for beginners to build logic.
string [] SomeArray = {"One","Two","Three"};
foreach (string value in SomeArray) {
if (value == "One") {
Console.WriteLine("Required string is: "+ value);
}
}