Dictionary + Tuple - object reference was not set [duplicate] - c#

This question already has answers here:
What is a NullReferenceException, and how do I fix it?
(27 answers)
Closed 13 days ago.
i have some letters in my config with x y coordinates.
i want to add key + x + y to my dictionary, but i dont get it work...
example config:
c|1807|833
Code:
private Dictionary<char, Tuple<int, int>> keyCoords;
...
string[] lines = File.ReadAllLines(filePath);
foreach (string line in lines)
{
string[] parts = line.Split('|');
if (parts.Length != 3)
{
continue;
}
char key = parts[0][0];
int x = int.Parse(parts[1]);
int y = int.Parse(parts[2]);
keyCoords[key] = Tuple.Create(x, y);
}
The last line keyCoords[key] = Tuple.Create(x, y); gives me a error:
The object reference was not set to an object instance.

We can get this down to a one-liner:
private Dictionary<char, (int, int)> keyCoords;
...
keyCoords = File.ReadLines(filePath).
Select(line => line.Split('|')).
Where(p => p.Length == 3).
ToDictionary(k => k[0][0], v => (int.Parse(v[1]), int.Parse(v[2])));
This solves the problem in the question by ensuring we never reference any members of the keyCoords variable before the object is created.
Note there is a subtle difference from the original, in that this will replace anything in keyCoords, where the original could have appended data. But if that were a likely situation we wouldn't have the null referece exception in the first place.

Related

Using concatenate to redefine an already defined string

I know a string is immutable and cannot be redefined, but in this foreach loop the string is changed multiple times by adding elements of an array.
var stringOfNames = "";
var arrayOfNames = new string[5] { "jack", "marry", "joe", "jimmy", "bud" };
foreach (var item in arrayOfNames)
{
stringOfNames += item;
Console.WriteLine(stringOfNames);
}
Expected:
An error stating "Variable is already defined in this scope."
Actual:
The string is changed by adding the other names.
Also, what's the difference between these two:
1)
var a = "something";
var a = "something else";
2)
var a = "something";
a+= "asdf";
Why does the second option work?
but in this foreach loop the string is changed
No, it's not.
The variable changes value, to refer to a different string on each iteration. Each of the string objects in question - both the original ones in the array and the intermediate results - stays with the same data that it had before.
Here's another way to demonstrate that:
string x = "ab";
string y = x;
x += "cd";
Console.WriteLine(x); // abcd
Console.WriteLine(y); // ab
Here the value of x changes to refer to a new string, but the value of y still refers to the original string, "ab".
Basically you need to be very clear about three separate concepts:
Variables: named storage locations which store values
References: one kind of value, which refers to an object.
The objects themselves
I have an answer on another question which may help clarify the differences.
stringOfNames += item; does not define the variable stringOfNames, it assigns a value to it.

C# Equivalent to Python's map()? [duplicate]

This question already has answers here:
Assign values of array to separate variables in one line
(8 answers)
Closed 4 years ago.
Normally in Python 2/3 we may use the following code to split two space-separated integers into two variables:
a,b = map(int,input().split())
Is there a short C# equivalent to this? (i.e nothing as long as below)
string[] template = Console.ReadLine().Split();
a = Convert.ToInt32(template[0]);
b = Convert.ToInt32(template[1]);
You could try this:
var result = Console.ReadLine().Split(' ').Select(int.Parse).ToArray();
However, the above code would crash if the input is not valid.
A more fault tolerant approach would be the following:
var result = Console.ReadLine()
.Split(' ')
.Select(input =>
{
int? output = null;
if(int.TryParse(input, out var parsed))
{
output = parsed;
}
return output;
})
.Where(x => x != null)
.Select(x=>x.Value)
.ToArray();
It's called Select(). You need to import Linq:
using System.Linq;
Then you can use it similar to map. Be aware that it is an extension function and is not the exact equivalent.
var integers = Console.ReadLine().Split().Select(s => Convert.ToInt32(s)).ToArray();
var a = integers[0];
var b = integers[1];
This example lacks any proper error handling.
Edit
Add ToArray()
Write out lambda, which is needed due to the overloads of Convert.ToInt32

How to sort Strings in C# [duplicate]

This question already has answers here:
C# sort Arraylist strings alphabetical and on length
(5 answers)
Closed 6 years ago.
I have to sort an array of strings. How can I do that, if:
They must be placed in order of string length.
If lengths are equal, the must be placed alphabetically.
Is there any simple to do that ?
Here's the traditional way in C# ...
static void Main(string[] args)
{
List<string> list = new List<string>();
list.Add("1991728819928891");
list.Add("0991728819928891");
list.Add("3991728819928891");
list.Add("2991728819928891");
list.Add("Hello");
list.Add("World");
list.Add("StackOverflow");
list.Sort(
delegate (string a, string b) {
int result = a.Length.CompareTo(b.Length);
if (result == 0 )
result = a.CompareTo(b);
return result;
}
);
Console.WriteLine(string.Join("\n", list.ToArray()));
}
Sample Output:
Hello
World
StackOverflow
0991728819928891
1991728819928891
2991728819928891
3991728819928891
You can do it with LINQ in the following way:
string[] arr = new[] { "aa", "b", "a" , "c", "ac" };
var res = arr.OrderBy(x => x.Length).ThenBy(x => x).ToArray();
Another way is to use Array.Sort with custom IComparer implementation.

how to find all the double characters in a string in c#

I am trying to get a count of all the double characters in a string using C#,i.e "ssss" should be two doubles not three doubles.
For example right now i have to do a for loop in the string like this
string s="shopkeeper";
for(int i=1;i<s.Length;i++) if(s[i]==s[i-1]) d++;
the value of d at the end should be 1
Is there a shorter way to do this? in linq or regex? and what are the perfomance implications, what is the most effective way? Thanks for your help
I have read [How to check repeated letters in a string c#] and
it's helpful, but doesn't address double characters, i am looking for
double characters
Try following Regex to extract any double characters: "(.)\1"
UPD: simple example:
foreach (var match in Regex.Matches("shhopkeeper", #"(.)\1"))
Console.WriteLine(match);
This works:
var doubles =
text
.Skip(1)
.Aggregate(
text.Take(1).Select(x => x.ToString()).ToList(),
(a, c) =>
{
if (a.Last().Last() == c)
a[a.Count - 1] += c.ToString();
else
a.Add(c.ToString());
return a;
})
.Select(x => x.Length / 2)
.Sum();
I gives me these results:
"shopkeeper" -> 1
"beekeeper" -> 2
"bookkeeper" -> 3
"boookkkeeeper" -> 3
"booookkkkeeeeper" -> 6
First I would like to mention that there is no "natural" LINQ solution to this problem, so every standard LINQ based solution will be ugly and highly inefficient compared to a simple for loop.
However there is a LINQ "spirit" solution to this and similar problems, like the linked How to check repeated letters in a string c# or if you want for instance finding not doubles, but let say triples, quadruples etc.
The common sub problem is, given a some sequence of elements, generate a new sequence of (value, count) pair groups for the consecutive elements having one and the same value.
It can be done with a custom extension method like this (the name of the method could be different, it's not essential for the point):
public static class EnumerableEx
{
public static IEnumerable<TResult> Zip<TSource, TResult>(this IEnumerable<TSource> source, Func<TSource, int, TResult> resultSelector, IEqualityComparer<TSource> comparer = null)
{
if (comparer == null) comparer = EqualityComparer<TSource>.Default;
using (var e = source.GetEnumerator())
{
for (bool more = e.MoveNext(); more;)
{
var value = e.Current;
int count = 1;
while ((more = e.MoveNext()) && comparer.Equals(e.Current, value)) count++;
yield return resultSelector(value, count);
}
}
}
}
Using this function in combination with standard LINQ, one can easily solve the original question:
var s = "shhopkeeperssss";
var countDoubles = s.Zip((value, count) => count / 2).Sum();
but also
var countTriples = s.Zip((value, count) => count / 3).Sum();
or
var countQuadruples = s.Zip((value, count) => count / 4).Sum();
or the question from the link
var repeatedChars = s.Zip((value, count) => new { Char = value, Count = count })
.Where(e => e.Count > 1);
etc.

ToUpper method for a string of words in a foreach loop not working [duplicate]

This question already has answers here:
ToUpper() method not working
(6 answers)
Closed 8 years ago.
I have a string array of names, and I want all the names to be in all caps.
This is my simple code, but it does not do anything to the names.
foreach (string x in names)
{
x.ToUpper();
Console.WriteLine("{0}", x);
}
You are not assigning back into the string (which is not required as well) do this -
foreach (string x in names)
{
Console.WriteLine("{0}", x.ToUpper());
}
From MSDN
Strings are immutable--the contents of a string object cannot be changed after the object is created, although the syntax makes it appear as if you can do this. For example, when you write this code, the compiler actually creates a new string object to hold the new sequence of characters, and that new object is assigned to b. The string "h" is then eligible for garbage collection.
You can also use:
names.ForEach(x => Console.WriteLine(x.ToUpper()));
Also, you must know that:
x.ToUpper(); creates new object in memory. And returns a copy of this string converted to uppercase. So you must assign it to a new varible:
string X = x.ToUpper();
Strings are immutable. So a new string is created which you need to assign to x.
foreach (string x in names)
{
var y = x.ToUpper();
Console.WriteLine("{0}", y);
}

Categories