Why converting List to Array not referencing in c#? - c#

An array in .Net is a reference type.
Given the two code segments above.
Question: why setting value varible "fixedItem" affects varible "data" in the first segment code, but the second segment code is does not affects
First code segment:
var data = new List<IList<int>>();
data.Add(new List<int>() { 1, 2, 3 });
data.Add(new List<int>() { 3, 8, 6,5 });
data.Add(new List<int>() { 1, 2 });
var fixedItem = data.Last();
fixedItem[1] = 8;
//Result:
//data = {{1,2,3}, {3,8,6,5}, {1,8}}
Second code segment:
var data = new List<IList<int>>();
data.Add(new List<int>() { 1, 2, 3 });
data.Add(new List<int>() { 3, 8, 6,5 });
data.Add(new List<int>() { 1, 2 });
var fixedItem = data.Last().ToArray();
fixedItem[1] = 8;
//Result:
//data = {{1,2,3}, {3,8,6,5}, {1,2}}

docs
according to documentation list.ToArray() method returns array with copies of original list

With the first version, fixedItem is the last item from the outer list, i.e. the third inner list. The same instance. Changing that list will be visible everywhere that list is referenced.
However, in the second version you use ToArray(), which creates a separate copy of the list contents, in a vector. You can do anything you like with your isolated copy - it is a different collection instance (and different collection type). Changing it will only be visible to things that reference the copy. The original list is unaffected because it is a different collection.

This is because with ToArray method, you have created a copy of the original list.
Official documentation
Copies the elements of the List to a new array.

There are many thing involve over here.
When you do ToArray in second segment , it actually create new variable and new collection.
Here you have created list of int, in this integer is value type so when it create new collection it copies those value and assign new memory location.
Now instead of int if you have created some reference type like object of class then if you change value over in one collection affect other. Here variable is new but it still reference the same memory location.

Look at the data types you've created after using Last() from Linq.
You receive two very different data types.
One would be a list while the other is just int[]. They have fairly different functionalities and ways to represent and handle data.

Related

How to assert all items in a collection to be different using fluent-assertions?

I want to make sure that all items in a collection to be different. How to do that?
Let's say:
IEnumerable collection = new[] { 1, 2, 5, 8 };
collection.Should().BeAllDifferent(); // NOTE: BeAllDifferent doesn't exist

c# how to best put array or list into class that also has name?

Instead of doing my old non OOP way I am trying to do what people claim is best. I need to store about 9 different Int arrays of differing lengths. I also need to associate them with a String Name "this is called etc.." I was thinking it would make sense to store that all into a class object so I can cleanly iterate through them later on without looking to two different places using the same for loop iterator.
Example:
public class Thing
{
public List<int> SDNA {get; set;}
public string Name {get; set;}
}
List<Thing> things = new List<Thing>
{
new Thing { SDNA = {2,4,5,7,9,11},Name = "First Thing"}
}
I get a null ref exception (I am assuming its cause of the list within a class somehow) I tried creating a list this way to clear the null ref but it had some other errors.
List<Thing> things = new List<Thing>();
things.Add(new Thing() {SDNA = {2,4,5,7,9,11},Name = "The first things name"});
Errors of invalid token etc. Should I just do it with two different stored arrays, one for names and a jagged array for the Ints and then reference them each? That feels ugly to me. Why can't I store them all into one thing?
Thanks!
In the simplest case if you want just to have name to value (array) association, you can try using a simple Dictionary, e.g.
private Dictionary<string, List<int>> things = new Dictionary<string, List<int>>() {
{"First thing", new List<int>() {2, 4, 5, 7, 9, 11}},
};
then you can use it
// Add new thing
things.Add("Some other thing", new List<int>() {1, 2, 3, 4, 5});
// Try get thing
if (things.TryGetValue("First thing", out var list)) {
// "First thing" exists, list is corresponding value
}
else {
// "First thing" doesn't found
}
// Remove "Some other thing"
things.Remove("Some other thing");
// Iterate over all {Key, Value} pairs (let's print them):
foreach (var pair in things)
Console.WriteLine($"{pair.Key} :: [{string.Join(", ", pair.Value)}]");
However, if Thing is not just SDNA + Name combination (more properties, methods are expected) I suggest
private Dictionary<string, Thing> things
declaration

Merge two list elements into json object

First list:
a=[0,1,2,3,4]
Second list:
b=[4.233,5.2324,6.342,3.233,8.435]
Is there any way to merge these two lists into a json object?
Ex: object: [{"a":0,"b":4.233},{"a":1,"b":5.2324},{"a":2,"b":6.342},{"a":3,"b":3.233},{"a":4,"b":8.435}]
Assuming you're working server side and have two arrays a and b,
var a = new[] {0, 1, 2, 3, 4};
var b = new[] {4.233, 5.2324, 6.342, 3.233, 8.435};
var c = a.Zip(b, (ai, bi) => new{a = ai, b = bi});
At this point, JsonConvert.SerializeObject(c) will output the example JSON you provided. You will need JSON.Net.
Zip() takes the nth element of both lists, and allows you to apply a function to each combination.

using TryGetValue from key and adding not working as intened

I have this code to retrieve a value(integer array) out of a dictionary Then increment one of the elements inside the integer array based on the if statement it is in..
Dictionary<string, int[]> ResultDic = new Dictionary<string, int[]>();
if (TeamOnePoint > TeamTwoPoint)
{
ResultDic.TryGetValue(TeamOneResult, out OutOfDic);
OutOfDic[0]++;
OutOfDic[1]++;
////ResultDic.Remove(TeamOneResult);
////ResultDic.Add(TeamOneResult, OutOfDic);
ResultDic[TeamOneResult] = OutOfDic;;
ResultDic.TryGetValue(TeamTwoResult, out OutOfDic);
OutOfDic[0]++;
OutOfDic[2]++;
////ResultDic.Remove(TeamTwoResult);
////ResultDic.Add(TeamTwoResult, OutOfDic);
ResultDic[TeamTwoResult] = OutOfDic;
}
Now the problem I have is that evertime I read the modified OutOfDic array back into the dictionary into the value part where I specified the Key, every value in the dictionary is modified as well, and not just the key I specified.
The commented part gives the same result as the non commented part. How do I fix this problem to only add the value to the specified key?
The behaviour you've described is only possible if you've added the same array to the dictionary multiple times. Since arrays are reference types every change will affect all values in the dictionay.
So instead of doing this(for example):
Dictionary<string, int[]> ResultDic = new Dictionary<string, int[]>();
int[] array = { 1, 2, 3, 4, 5 };
ResultDic.Add("TeamOne", array);
ResultDic.Add("TeamTwo", array);
You should do this:
int[] array = { 1, 2, 3, 4, 5 };
ResultDic.Add("TeamOne", array);
array = new int[] { 1, 2, 3, 4, 5 };
ResultDic.Add("TeamTwo", array);
Note that it's not necessary to re-assign the array to the dictionary for the same reason (it's a reference type). So you can remove these lines:
ResultDic[TeamOneResult] = OutOfDic;;
// ....
ResultDic[TeamTwoResult] = OutOfDic;

Sorting an array related to another array

I have two arrays, x and y, where y is the value of the tens of every element in x. Now, I want to sort y. But, the order of y will be different of x's. So, I can't tell after sorting which element in y was related to, for instance, x[0].
I want a "double sorting" maybe.
Array.Sort has an overload that accepts two arrays; one for the keys, and one for the items. The items of both are sorted according to the keys array:
int[] keys = { 1, 4, 3, 2, 5 };
string[] items = { "abc", "def", "ghi", "jkl", "mno" };
Array.Sort(keys, items);
foreach (int key in keys) {
Console.WriteLine(key); // 1, 2, 3, 4, 5
}
foreach (string item in items) {
Console.WriteLine(item); // abc, jkl, ghi, def, mno
}
So in your case, it sounds like you want:
Array.Sort(y,x); // or Sort(x,y); - it isn't 100% clear
How about?
var selectedArr = new int[] { 1, 3, 5, 7, 9 };
var unorderArr = new int[] { 9, 7, 5, 3, 1 };
var orderedArr = unorderArr.OrderBy(o => selectedArr.IndexOf(o));
If we have two arrays of complex objects and want to sort them according to one of the two arrays then we can use the next approach:
// We want to sort "people" array by "Name" and
// accordingly to it reorder "countries" array.
Person[] people = new Person[]
{
new Person {Name = "Fill"},
new Person {Name = "Will"},
new Person {Name = "Bill"},
};
Country[] countries = new Country[]
{
new Country {Name = "Canada"},
new Country {Name = "UK"},
new Country {Name = "USA"}
};
// Here we sort "people" array, but together with each "Person"
// in sorted array we store its "index" in unsorted array. Then we
// will use this "index" to reorder items in "countries" array.
var sorted = people
.Select((person, index) => new {person, index})
.OrderBy(x => x.person.Name)
.ToArray();
// Here "people" array is sorted by "Name", and
// "contries" array is reordered accordingly to it.
people = sorted.Select(x => x.person).ToArray();
countries = sorted.Select(x => countries[x.index]).ToArray();
Another approach is to use overload of the method Array.Sort with IComparer. At first we should implement IComparer:
private class PeopleComparer : IComparer<Person>
{
public int Compare(Person x, Person y)
{
return x.Name.CompareTo(y.Name);
}
}
And then we can sort two our arrays:
Array.Sort(people, countries, new PeopleComparer());
Here is complete sample that demonstrates these two approaches.
If y is always the tens value of x, y probably shouldn't exist - you should probably just calculate it's value directly off of x when needed.
In general, sorting parallel arrays is only possible (without hand rolling a sort algorithm) when the sort algorithm takes a custom "swap" function, which you can implement in terms of swapping elements in both arrays simultaneously. std::sort in C++ and qsort in C don't allow this.
Also in the general case, consider a single array where the element is a pair of items, rather than a parallel array for each item. This makes using "standard" algorithms easier.

Categories