Getting Value from dictionary, when the key in an object - c#

I have an object PixelData:
public class PixelData
{
public int X {get;set;}
public int Y {get;set;}
}
pixel data is a key to a dictionary.
Dictionary<PixelData, int> dict
how do i use pixel data the right way?

A very simple solution would be to use a struct instead of a class for PixelData:
public struct PixelData
{
public int X;
public int Y;
}
var dict = new Dictionary<PixelData, int>();
You can read about the differences between structs and classes in C# here. Short version: structs are value types, unlike classes which are reference types. Therefore, if you want to retrieve a value from the dictionary, you don't need a reference to the original PixelData instance which was used as the key. You can go ahead and create a new instance, with the exact same X and Y you used for the key, and it will work just fine.
// Add new value to dictionary with new PixelData instance as the key
dict.Add(new PixelData { X = 1, Y = 1 }, 42);
// Retrieving the value using a new, but identical instance of PixelData works just fine
int value = dict[new PixelData { X = 1, Y = 1 }]);

If X and Y are public properties, then below query can be used to retrieve the matching dictionary value. This query assumes that 'searchingForItem' is the PixelData Item, you are looking to find in dict.
var matchingItem = dict.FirstOrDefault(p => p.Key.X.Equals(searchingForItem.X) && p.Key.Y.Equals(searchingForItem.Y));

Related

Using struct in dictionary as a value

Hi I have a struct and dictionary as below and I'm trying to add it as a custom value
like
public struct data_inv
{
//protected static int p;
public float inventory;
public float supply;
public float demand;
};
public static IDictionary<int, data_inv> inv_stored = new Dictionary<int, data_inv>();
and I have tried to add value to dictionary but when I try to add a value like inv_stored[1].demand = 4;
its gives System.Collections.Generic.KeyNotFoundException: 'The given key was not present in the Dictionary.' exception. I'm new to coding, could any explain what im doing wrong
If you want to use a struct instead of a class, write this instead of inv_stored[1].demand = 4 (updated based on comments):
public struct data_inv
{
public float Inventory;
public float Supply;
public float Demand;
public data_inv(int demand)
{
Inventory = 0;
Supply = 0;
Demand = demand;
}
};
// ....
IDictionary<int, data_inv> inv_stored = new Dictionary<int, data_inv>();
data_inv myData = new data_inv(4);
inv_stored.Add(1, myData);
This is a way to add keyValue to a Dictionary.
data_inv shouldn't be a struct. It's mutable, and structs shouldn't be mutable, it's not representing a single value. You should make it a class instead.
public class data_inv
{
//protected static int p;
public float inventory;
public float supply;
public float demand;
};
Implementation:
// Add new item into dictionary
inv_stored.Add(1, new data_inv()
{
inventory = 20,
supply = 10,
demand = 5
});
Console.WriteLine(inv_stored[1].demand); // 5
inv_stored[1].demand = 4;
Console.WriteLine(inv_stored[1].demand); // 4
Edit:
Print all elements each in one line:
foreach (var kvp in inv_stored)
{
Console.Write("bucket:{0} ", kvp.Key);
Console.Write("inventory:{0}, ", kvp.Value.inventory);
Console.Write("supply:{0}, ", kvp.Value.supply);
Console.WriteLine("demand:{0}", kvp.Value.demand);
}
Example output:
bucket:1 inventory:20, supply:10, demand:4
bucket:2 inventory:16, supply:9, demand:7
Print all elements into a table format:
var buckets = inv_stored.Keys;
var inventory = inv_stored.Values.Select(x => x.inventory);
var supply = inv_stored.Values.Select(x => x.supply);
var demand = inv_stored.Values.Select(x => x.demand);
Console.WriteLine("buckets:\t{0}", string.Join("\t", buckets));
Console.WriteLine("inventory:\t{0}", string.Join("\t", inventory));
Console.WriteLine("supply: \t{0}", string.Join("\t", supply));
Console.WriteLine("demand: \t{0}", string.Join("\t", demand));
Example Output:
buckets: 1 2 3
inventory: 20 16 56
supply: 10 9 44
demand: 4 7 23
There's multiple problems with your code.
First, you can create a new record in a dictionary by doing something like dict[key] = value;. However, you can not do dict[key].field = value;. The setter can be used with non-existent keys, the getter can't.
Second, while you can use structs as values in a dictionary, you cannot set their fields directly. Structs use value-type semantics by default (i.e. whenever you don't explicitly use ref or take a pointer), so any change you made this way would be done to a copy of the struct, not the actual value in the dictionary. You can use something like this:
var val = dict[key];
val.field = newFieldValue;
dict[key] = val;
Third, it's generally considered bad practice to use mutable structs, exactly because of these complications. Mutable structs only have place in highly optimised code and native interop, and they need to be carefully tested and monitored. Heck, even many automated refactorings can break code with mutable structs.

How to cast an array of structures (of double values) to an array of double values

I am trying to create a wrapper to treat System.Numeric.Complex array as array of double, i.e. to treat {{1,2},{3,4},{5,6},{7,8} as {1,2,3,4,5,6,7,8}. I use these arrays for FFT so this way will be more efficient because avoids copying and iterating huge arrays. But i stuck on a strange chimeric monster: A Double array object of kind double[] {System.Numerics.Complex[4], instead of double[8]!!. What's that?
I am not an interop expert so excuse any essential blunder; I read some related stuff here and here and I wonder if the case is that these arrays are overlapped. Τhis code almost works except for that it returns half of the values:
//using System.Runtime.InteropServices;
//using System.Numeric;
[StructLayout(LayoutKind.Explicit)]
public struct ComplexArray2serialWrapper
{
[FieldOffset(0)] private Complex[] ComplexArray;
[FieldOffset(0)] private double[] DoubleArray;
public ComplexArray2serialWrapper(Complex[] NewcomplexArray) : this() { ComplexArray = NewcomplexArray; }
public ComplexArray2serialWrapper(double[] NewSerialComplexArray) : this() { DoubleArray = NewSerialComplexArray; }
public static implicit operator double[] (ComplexArray2serialWrapper source) { return source.DoubleArray; }
}
public static void TestWrapper()
{
Complex[] cc = { new Complex(1, 2), new Complex(3, 4), new Complex(5, 6), new Complex(7, 8) };
double[] DoubleComplexChimeraMonster = new ComplexArray2serialWrapper(cc);
var parenttype = DoubleComplexChimeraMonster.GetType(); // result = System.Numerics.Complex[]
//!!! but in watch window type shown as= double[] {System.Numerics.Complex[4]}
var ChildrenType = DoubleComplexChimeraMonster[0].GetType(); //System.Double
//In Watch window, children types shown chimeric:
//{ (1, 2)} Double {System.Numerics.Complex}
//{ (3, 4)} Double {System.Numerics.Complex}
//{ (5, 6)} Double {System.Numerics.Complex}
//{ (7, 8)} Double {System.Numerics.Complex}
double i1 = DoubleComplexChimeraMonster[0]; //=1 (as expected)
double i2 = DoubleComplexChimeraMonster[1]; //=2 (as expected)
double i3 = DoubleComplexChimeraMonster[2]; //=3 (as expected)
double i4 = DoubleComplexChimeraMonster[3]; //=4 (as expected)
var l = DoubleComplexChimeraMonster.Length; //=4 (8 expected)
//So trying to get i5-i8 will throw an exception e.g.:
//DoubleComplexChimeraMonster(4) --> exception (5 expected)
}
You expect the arrays to store only the doubles. But they also store the array length and a reference to a type descriptor. Therefore, your approach of overlapping two .NET types does not work. C# is not C.
DoubleComplexChimeraMonster is statically typed as double[], however GetType() retrieves the runtime type, which happens to be Complex[].
Overlapping values at the same memory location works for primitive value types. But System.Array is a class.
As Marc Gravell says in this answer of the link you provided, unsafe pointers might be the way to go.

C# Infinite While Loop using ContainsValue with nested Dictionary

I have this script in PHP where I use
while( in_array(array('x' => $x, 'y' => $y), $worldMap) ){ ... }
to check if my worldMap already have a room at those XY positions.
IF TRUE I randomize either X or Y and the WHILE loop check again with the new values and so on, IF FALSE I populate the worldMap array with last XY generated.
Now, I'm trying to rewrite that code in C# but I'm getting an infinite Loop.
Here's my current Code:
public int nbRooms = 10;
private Dictionary<int, Dictionary<string, int>> worldMap = new Dictionary<int, Dictionary<string, int>>();
private Dictionary<string, int> roomXY = new Dictionary<string, int>();
private string[] arrayXY = {"X","Y"};
private int[] arrayNbr = {-1,1};
private int X = 0;
private int Y = 0;
for(int i = 0; i <= nbRooms; i++)
{
while(worldMap.ContainsValue(roomXY))
{
string XorY = arrayXY[Random.Range(0, 2)];
switch(XorY)
{
case "X": X += arrayNbr[Random.Range(0, 2)];
break;
case "Y": Y += arrayNbr[Random.Range(0, 2)];
break;
}
roomXY.Clear();
roomXY.Add("X", X);
roomXY.Add("Y", Y);
}
worldMap.Add(i, roomXY);
}
The basic issue here is that, by default, a comparison between two reference type objects simply compares the reference itself. While you change the contents of the roomXY object, you do not change the reference itself (i.e. the actual object remains the same), and so once you have added the object to your worldMap dictionary once, it is always there when you check the next time through the loop.
A very good illustration of why when porting code it's important to port the intent but not necessarily the exact implementation, due to differences in the way the language handles things.
In fact, based on the code you've posted, it seems as though you probably don't want to use a dictionary class anywhere in this case. It can be made to work using dictionary objects, but you aren't really taking advantage of the dictionary-like nature of those data structures. It seems like you are using dictionaries here more because semantically they seem to operate similarly to the data structures you were using in PHP, but in fact C# offers other language features that would probably be more appropriate.
For example, you could have written your code like this:
struct Room
{
public readonly int X;
public readonly int Y;
public Room(int x, int y) { X = x; Y = y; }
}
public int nbRooms = 10;
private Room[] worldMap = new Room[nbRooms];
private string[] arrayXY = {"X","Y"};
private int[] arrayNbr = {-1,1};
private int X = 0;
private int Y = 0;
private Room roomXY = new Room(X, Y);
for(int i = 0; i <= nbRooms; i++)
{
while(Array.IndexOf(worldMap, roomXY) >= 0)
{
string XorY = arrayXY[Random.Range(0, 2)];
switch(XorY)
{
case "X": X += arrayNbr[Random.Range(0, 2)];
break;
case "Y": Y += arrayNbr[Random.Range(0, 2)];
break;
}
roomXY = new Room(X, Y);
}
worldMap[i] = roomXY;
}
Because of the way C# implements equality comparisons by default for value types (i.e. a struct), this will compare the actual contents of the roomXY value against the values found in worldMap.
Note: both your original implementation and the one above use a linear search in the worldMap data structure. For the small number of rooms here (10), this should be fine. But you should be aware that this can be very inefficient for larger sets of data. You will likely want to use a different approach to generate this data in that case (e.g. hash set, flags in a larger map data structure, shuffling, etc.).
ContainsValue uses the default equality comparer EqualityComparer.Default for TValue, the type of values in the dictionary. roomXY is a (reference to) dictionary object, the reference is not changing by changing the X and Y coordinates of this object so you run into an infinite while loop.

How can I replace int values in a dictionary C#

I am wondering how I could replace int values in a dictionary in C#.
The values would look something like this.
25,12
24,35
12,34
34,12
I was wondering how I could only replace one line. For example if I wanted to replace the first line with a new value of 12,12. And it wouldn't replace any of the other '12' values in the dictionary.
A Dictionary<TInt, TValue> makes use of what are known as indexers. In this case, these are used to access elements in the dictionary by key, hence:
dict[25] would return 12.
Now, according to what you want to do is to have a key of 12 and a value of 12. Unfortunately, you cannot replace entries in a dictionary by key, so what you must do is:
if(dict.ContainsKey(25))
{
dict.Remove(25);
}
if(!dict.ContainsKey(12))
{
dict.Add(12, 12);
}
Note: In the values you supplied, there is already a key-value pair with 12 as its key, so you would not be allowed to add 12,12 to the dictionary as if(!dict.ContainsKey(12)) would return false.
You cannot replace the first line with 12, 12 because there is another key value pair with 12 as it's key. And you cannot have duplicate keys in a dictionary.
Anyway you may do such things like this:
Dictionary<int, int> myDictionary = new Dictionary<int, int>();
myDictionary.Add(25, 12);
myDictionary.Add(24, 35);
//remove the old item
myDictionary.Remove(25);
//add the new item
myDictionary.Add(12, 12);
EDIT: if you are going to save some x,y positions I would suggest you creating a class named Point and use a List<Point>. Here is the code:
class Point
{
public double X {get; set;}
public double Y {get; set;}
public Point(double x, double y)
{
this.X = x;
this.Y = y;
}
}
Then:
List<Point> myList =new List<Point>();
myList.Add(new Point(25, 13));
In Dictionaries, the keys must be unique.
In case the key need not be unique, you could use a List<Tuple<int, int>> or List<CustomClass> with CustomClass containing two integer fields. Then you may add or replace the way you want.

2D Array, program crash

Here's a piece of code coming from a C# project using a 2d array. For a reason I don't understand my program compiles perfectly but during run-time it crashes.
public class Tile_Info
{
public int id;
public Tile_Info(int _id)
{
id = _id;
}
}
class Program
{
public static void Main(string[] args)
{
int width = 20;
int height = 30;
Tile_Info[,] my_tile;
my_tile = new Tile_Info[width, height];
for(int y = 0; y < height; y++)
{
for(int x = 0; x < width; x++)
{
my_tile[x, y].id = 0;
}
}
}
}
According to the debugger it's because "Object reference not set to an instance of an object", but I'm pretty sure it's what I'm doing here: my_tile = new Tile_Info[width, height];.
Anyone can tell what's wrong? Thank you for your support!
The creation of the array does not create the objects themselves, just like a creation of a parking lot does not create the cars that park there.
You still need to create the objects yourself. Change
my_tile[x, y].id = 0;
to
my_tile[x, y] = new Tile_Info(0);
This only happens when reference types (class) are used because the thing that is stored in the array is a reference to an instance, instead of the instance itself. On a lower level this (more or less) means that the memory for the instance is not yet allocated, just the memory for its reference, so you must new up an instance to initialize it. On the other hand if Tile_Info is a value type (struct) then the array will contain the actual instance, and the new Tile_Info[width, height] would have initialized the allocated memory to valid start state (all zeroes), which is exactly what the default parameterless constructor of a value type does.
So, if you had defined Tile_Info like this:
public struct Tile_Info
{
public int id; // this should be a property, public fields are baaad
public Tile_Info(int _id){ id = _id;}
}
both my_tile[x, y].id = 0 and my_tile[x, y] = new Tile_Info(0) would have been legal.
You have created a new 2D Tile_Info array by the first new keyword.
You have only created an empty array that can hold items of type Tile_Info. Its your job to create individual items and put them in the array.

Categories

Resources