I have Struct
struct User
{
public int id;
public Dictionary<int, double> neg;
}
List<User> TempUsers=new List<users>();
List<User> users = new List<User>();
my Problem is, when I run this code
TempUsers=users.ToList();
TempUsers[1].neg.Remove(16);
neg dictionary in users aslo remove key with value=16
That is because the Dictionary is a reference type. You should clone it, for sample:
class User : IClonable
{
public int Id { get; set; }
public Dictionary<int, double> Neg { get; set; }
public object Clone()
{
// define a new instance
var user = new User();
// copy the properties..
user.Id = this.Id;
user.Neg = this.Neg.ToDictionary(k => k.Key,
v => v.Value);
return user;
}
}
You shouldn't use a struct in a type like this. In this link, there is a good explanation about when and how you should use a struct.
Dictionary is a reference type. You should clone you dictionary:
this is an example:
struct User : ICloneable
{
public int id;
public Dictionary<int, double> neg;
public object Clone()
{
var user = new User { neg = new Dictionary<int, double>(neg), id = id };
return user;
}
}
Related
I have a List which I would like to populate with different types of objects, trying to do it with object\dynamic, but it doesn't, even when casting.
using asp.net core.
See my code:
public Dictionary<string, Employee> getEmployees(); //This method returns a dictionary of string as a key and Employee as a value.
public Dictionary<string, customer>()> getCustomers(); //same principal
public List<Dictionary<string, object>> getDifferentItems()
{
List<Dictionary<string, object>> listOfItems = new List<Dictionary<string, object>>();
listOfItems.add(getEmployees()); //Error
listOfItems.add(getCustomers()); //Error
return listOfItems;
}
Depending on what you are trying to do, I can see two solutions:
Create a list of TWO different dictionaries
public Dictionary<string, Employee> getEmployees() {
return new Dictionary<string, Employee>();
}
public Dictionary<string, Customer> getCustomers() {
return new Dictionary<string, Customer>();
}
public List<Dictionary<string, object>> getDifferentItems()
{
List<Dictionary<string, object>> listOfItems = new List<Dictionary<string, object>>();
listOfItems.Add(this.getEmployees().ToDictionary(entry => (string)entry.Key,
entry => (object)entry.Value));
listOfItems.Add(this.getCustomers().ToDictionary(entry => (string)entry.Key,
entry => (object)entry.Value));
return listOfItems;
}
Create one dictionary with all the values
public Dictionary<string, Employee> getEmployees() {
return new Dictionary<string, Employee>();
}
public Dictionary<string, Customer> getCustomers() {
return new Dictionary<string, Customer>();
}
public Dictionary<string, object> getDifferentItems()
{
Dictionary<string, object> listOfItems = new Dictionary<string, object>();
foreach (var entry in getEmployees()) {
listOfItems.Add(entry.Key, entry.Value);
}
foreach (var entry in getCustomers()) {
listOfItems.Add(entry.Key, entry.Value);
}
return listOfItems;
}
There are a couple of issues here, both related to variance.
This won't work because List<T>, or any other class in .NET for that matter, does not support variance.
In other words T has to be a specific type, and does not respect inheritance / substitutability as with non-generic types.
Similarly, for Dictionary<TKey, TValue>, TValue is not variant, so you can't simply use object as the value.
IEnumerable<out T> on the other hand is covariant so you could do this:
public IEnumerable<IDictionary> getDifferentItems()
{
yield return getEmployees();
yield return getCustomers();
}
IDictionary is used, as it is the only common ancestor (other than object) to Dictionary<string, Employee> and Dictionary<string, Customer>.
This may satisfy your requirements, but you don't make clear whay you are trying to achive with your getDifferentItems method.
More information on variance can be found here.
I'd personally make an interface, such as IPerson that has all the properties of Employees and Customers, such as Name, Address, ID, etc.
Set up your Customer and employee classes to implement IPerson
Then use a IPerson in your dictionary and you can add to the objects to that.
Here's some code:
public class Employee : IPerson
{
public int ID { get; set; }
public string Name { get; set; }
}
public class Customer : IPerson
{
public int ID { get; set; }
public string Name { get; set; }
}
public interface IPerson
{
int ID { get; set; }
string Name { get; set; }
}
public class Test
{
public void MyTest()
{
List<Dictionary<string, IPerson>> listOfItems = new List<Dictionary<string, IPerson>>();
Dictionary<string, IPerson> myEmployees = new Dictionary<string, IPerson>();
string someString = "blah";
Employee e = new Employee();
e.Name = "Bob";
e.ID = 1;
myEmployees.Add(someString, e);
Dictionary<string, IPerson> myCustomers = new Dictionary<string, IPerson>();
string someOtherString = "blah";
Customer c = new Customer();
c.Name = "Robert";
c.ID = 2;
myCustomers.Add(someOtherString, c);
listOfItems.Add(myEmployees);
listOfItems.Add(myCustomers);
}
}
Here is another solution :
public class Test
{
Dictionary<string, object> listOfItems = new Dictionary<string, object>();
List<Employee> employees = new List<Employee>();
List<customer> customers = new List<customer>();
public Dictionary<string, object> getEmployees()
{
return employees.GroupBy(x => x.name, y => (object)y).ToDictionary(x => x.Key, y => y.FirstOrDefault());
}//This method returns a dictionary of string as a key and Employee as a value.
public Dictionary<string, object> getCustomers()
{
return customers.GroupBy(x => x.name, y => (object)y).ToDictionary(x => x.Key, y => y.FirstOrDefault());
} //same principal
public Dictionary<string, object> getDifferentItems()
{
listOfItems = getEmployees();
listOfItems.Concat(getCustomers());
return listOfItems;
}
}
public class Employee
{
public string name { get;set;}
}
public class customer
{
public string name { get;set;}
}
I am learning C# dictionary and I am confused how to do this
I have a Dictionary of students names. and I would like to assign another dictionary to that.
my input similar to this
Student1:
Math,9
Science,5
English,2
Student2:
Math,9
Science,10
English,7
I tried to create a class called Info and here is my code
public class Info
{
public string course { get; set; }
public int grade { get; set; }
public Info(string c, int g)
{
course = c;
grade = g;
}
internal IDictionary<string, Info> infoDic { get; private set; }
public void Set(string Sname, string course, int grade)
{
Student s = new Student(Sname);
var infor = new Info(course, grade);
infoDic = new Dictionary<string, Info>();
infoDic.Add(s.Name, infor);
//return infoDic;
}
public Dictionary<string, Info> retrieve (string name)
{
Student s = new Student(name);
return infoDic;
}
}
}
and here is another attempt:
I tried to make the class Info , and in the main I create the Dictionary and give the values, but the problem is I have lets say 3 courses and 10 students, and sometimes I need to retrieve only the math grades for all students.
How to improve the code to differentiate between the courses? Or how to make the course name as another key?
public class Info
{
public string course { get; set; }
public int grade { get; set; }
public Info(string c, int g)
{
course = c;
grade = g;
}
}
class Test
{
public static void Main(string[] args)
{
Dictionary<string, Info> information = new Dictionary<string, Info>();
Info i1 = new Info("math", 9);
information.Add("Student1", i1);
Info i2 = new Info("science", 11);
information.Add("Student1", i2);
Info i3 = new Info("math", 13);
information.Add("student2", i3);
foreach (KeyValuePair<string, Info> eee in information)
{
Console.WriteLine("{0}\t{1}\t{2}", eee.Key, eee.Value.type, eee.Value.count);
}
}
}
I need two methods one to set the values that user enters and the other to retrieve a certain course values when the user requires them
Is there Any suggestions?
Split the problem into separate concerns.
Use the Student and Info classes just to store data. Importantly, every Student holds a collection of his courses.
public class Student {
public Student(string name) {
Name = name;
Infos = new List<Info>();
}
public string Name {get; set;}
public ICollection<Info> Infos {get; set;}
}
public class Info {
public Info(string course, int grade) {
Course = course;
Grade = grade;
}
public string Course { get; set; }
public int Grade { get; set; }
}
Data access is handled by a different class StudentRepository.
The central dictionary is of type IDictionary<string, Student> with the Student name as key and hidden inside the repository.
using System.Linq;
public class StudentRepository {
public StudentRepository() {
_studentsByName = new Dictionary<string, Student>();
}
// keep data store private so we can change the implementation
private IDictionary<string, Student> _studentsByName {get; set;}
public void Add(Student student) {
if (_studentsByName.ContainsKey(student.Name)) {
throw new ArgumentException($"Student '{student.Name}' already stored.");
}
_studentsByName.Add(student.Name, student);
}
public Student Get(string studentName) {
if (_studentsByName.ContainsKey(studentName)) {
return _studentsByName[studentName];
}
throw new ArgumentException("No student '" + studentName + "' stored.");
}
// Find Grade for certain student and course
public int GetGrade(string studentName, string course) {
if (_studentsByName.ContainsKey(studentName)) {
var student = _studentsByName[studentName];
var courseInfo = student.Infos.FirstOrDefault(i => i.Course == course);
if (courseInfo != null) {
return courseInfo.Grade;
}
else {
throw new ArgumentException(
$"Student '{studentName}' did not take the course '{course}'.");
}
}
else {
throw new ArgumentException($"No student '{studentName}' found.");
}
}
// Get dictionary of all students that took a certain course. Key: student name
public IDictionary<string, Info> GetCoursesByStudentName(string course) {
// Use LINQ to retrieve the infos you need.
// Here I create a new dictionary with Student name as Key and
// the first matching course info found as value.
// (Students that did not take this course are not in this dictionary):
return _studentsByName
.Where(kvp => kvp.Value.Infos.Any(i => i.Course == course))
.ToDictionary(kvp => kvp.Key,
kvp => kvp.Value.Infos.First(i => i.Course == course));
}
}
Usage example:
const string MathCourseName = "Math";
var Student1 = new Student("Alice");
Student1.Infos.Add(new Info(MathCourseName, 4));
var Student2 = new Student("Bob");
Student2.Infos.Add(new Info(MathCourseName, 2));
var Student3 = new Student("Cesar");
Student3.Infos.Add(new Info("English", 3));
var repository = new StudentRepository();
repository.Add(Student1);
repository.Add(Student2);
repository.Add(Student3);
foreach(var kvp in repository.GetCoursesByStudentName(MathCourseName)) {
Console.WriteLine(kvp.Key + ": " + kvp.Value.Course + " - " + kvp.Value.Grade);
}
var bobsMathGrade = repository.GetGrade("Bob", MathCourseName);
Console.WriteLine("Bobs math grade: " + bobsMathGrade);
C# Fiddle for this example
What i understood from your statement, you need two methods: One for setting user values and other for getting user's course value, i've slightly modified your code in order to fulfill you requirement, you can do like this:
public class Info
{
public string course { get; set; }
public int grade { get; set; }
public Info(string c, int g)
{
course = c;
grade = g;
}
}
public class Student
{
public Dictionary<string,Dictionary<string,int>> student { get; set; }
public Student()
{
student = new Dictionary<string, Dictionary<string, int>>();
}
/// <summary>
///
/// </summary>
public void SetValue(string studentName, Info info)
{
if (!student.ContainsKey(studentName))
{
Dictionary<string, int> stud_info = new Dictionary<string, int>();
stud_info.Add(info.course, info.grade);
student.Add(studentName, stud_info);
}
else
{
student[studentName].Add(info.course, info.grade);
}
}
public Dictionary<string,int> GetValue(string studentName, string course)
{
Dictionary<string, int> info = new Dictionary<string, int>();
if (student.ContainsKey(studentName))
{
if (student[studentName].ContainsKey(course))
{
int grade = 0;
if(student[studentName].TryGetValue(course, out grade))
{
info.Add(course, grade);
return info;
}
}
}
return info;
}
}
public class Program
{
public static void Main(string[] args)
{
Student student = new Student();
Info i1 = new Info("math", 9);
student.SetValue("Student1", i1);
Info i2 = new Info("science", 11);
student.SetValue("Student1",i2);
Info i3 = new Info("math", 13);
student.SetValue("Student2", i3);
Dictionary<string, int> value = student.GetValue("Student2", "math");
//Grade of math for student2
Console.WriteLine("Grade: {0}", value["math"]);
}
}
I ran into a problem I cannot solve. :-) I have to find all the values which contains a certain substring then I must get back the key and value pair. I had to implement a system where I had to make a SortedList, where the Albums is a class string is the key of course
Albums alb = new Albums();
SortedList<string, Albums> list1 = new SortedList<string, Albums>();
The Albums class looks like this:
public class Albums : IComparable
{
public string albname;
public string name1;
public string releasedate;
public Guid albumID;
public Albums()
{
albumID = new Guid();
}
public override string ToString()
{
return "Album: " + Albname + "\t" + Releasedate;
}
public Albums(string albname, string releasedate)
{
this.albname = albname;
this.releasedate = releasedate;
}
public string Name1
{
get { return name1; }
set { name1 = value; }
}
public string Albname
{
get { return albname; }
set { albname = value; }
}
public string Releasedate
{
get { return releasedate; }
set { releasedate = value; }
}
public int CompareTo(object obj)
{
if (obj is Albums)
{
Albums other = (Albums)obj;
return albname.CompareTo(other.albname);
}
if (obj is string)
{
string other = (string)obj;
return releasedate.CompareTo(releasedate);
}
else
{
return -999;
}
}
}
What I tried at last that I put the Albums into a LinkedList:
LinkedList<string> albm1 = new LinkedList<string>();
I did manage to find all the Albums that contains the substring using IEnumerable:
string albsearch = textBox16.Text;
IEnumerable<string> result = albm1.Where(s => s.Contains(albsearch));
BUT I do not know how to compare result to the Values of the SortedList. I also tried to create a new SortedList which contains the album in string:
SortedList<string, string> list2 = new SortedList<string, string>();
Any suggestion would be appreciated. Thanks in advance!
When you enumerate a SortedList, each item in the enumeration is a key/value pair.
I think what you want is:
Albums alb = new Albums();
SortedList<string, Albums> list1 = new SortedList<string, Albums>();
var foundItems = list1.Where(item => item.Key.Contains(albsearch));
Or, if you want to search in the Album:
var foundItems = list1.Where(item => item.Value.albname.Contains(albsearch));
Of course, you could search the name1 field rather than the album name, if that's what you want.
Each item returned is a key/value pair. More correctly, a KeyValuePair<string, Album>.
[Test]
public void Allbum_Search_Test()
{
var searchText = "TestA";
var list1 = new SortedList<string, Albums>
{
{"TestAlbum1", new Albums("TestAlbum1","SomeDate")},
{"TestAlbum2", new Albums("TestAlbum2","SomeDate")},
{"OtherAlbum2", new Albums("OtherAlbum","SomeDate")}
};
var results = list1.Where(pair => pair.Key.Contains(searchText));
Assert.That(results.Count(), Is.EqualTo(2));
}
On another note i would highly recommend
making the fields private
renaming Albums to Album
changing the ReleaseDate type to DateTime
renaming Albname to AlbumName
How can I create a list which holds both string value and int value?
Can anyone help me please.Is it possible to create a list with different datatypes?
You could use:
var myList = new List<KeyValuePair<int, string>>();
myList.Add(new KeyValuePair<int, string>(1, "One");
foreach (var item in myList)
{
int i = item.Key;
string s = item.Value;
}
or if you are .NET Framework 4 you could use:
var myList = new List<Tuple<int, string>>();
myList.Add(Tuple.Create(1, "One"));
foreach (var item in myList)
{
int i = item.Item1;
string s = item.Item2;
}
If either the string or integer is going to be unique to the set, you could use:
Dictionary<int, string> or Dictionary<string, int>
List<T> is homogeneous. The only real way to do that is to use List<object> which will store any value.
You can make have the list contain any object you like. Why don't you create a custom object
Custom Object
public class CustomObject
{
public string StringValue { get; set; }
public int IntValue { get; set; }
public CustomObject()
{
}
public CustomObject(string stringValue, int intValue)
{
StringValue = stringValue;
IntValue = intValue;
}
}
List Creation
List<CustomObject> CustomObject = new List<CustomObject>();
Broadcom
Connection Name: Local Area Connection
DHCP Enabled: No
IP address(es)
[01]: abc.de.fg.h
I would like to put this into a Dictionary<string, Dictionary <string, string>>
So Broadcom would be the key in the first dictionary and the rest would be value the value. The value should be stored as a dictionary where Connection Name is the key and Local Area Connection is the value. How do I go about doing that? I am new to programming. Thanks for the help.
Please do yourself a great favour and use a class for that, because in two months time you will not understand your code:
public class WhatIsThis {
private List<IPAddress> ipAddresses = new List<IPAddress>();
public string Name { get; set; }
public string ConnectionName { get; set; }
public bool DHCPEnabled { get; set; }
public List<IPAddress> IPAddresses { get return ipAddresses; }
}
Now you can keep a List<WhatIsThis> around. If you have justa few of them, the O(n) cost of looking a value up is negligible. If you want a lookup by name in O(1) fashion, you can map to a Dictionary as such:
var dict = listOfWhatisThis.ToDictionary(k=>k.Name, v=>v}
Gives you a Dictionary of type Dictionary<string,WhatIsThis> . What do you think, will you understand this better in 2 weeks time, or rather your scary Dictionary?
http://msdn.microsoft.com/en-us/library/bb531208.aspx
var dic = new dictionary<string, dictionary <string, string>>(
{"Broadcom",
new dictionary <string, string>(
{
{"Connection Name", "Local Area Connection"},
{"DHCP Enabled", "No"},
{"IP address(es) [01]", "abc.de.fg.h"}
}
)
}
);
My only concern would be that the IP Addresses should themselves be in a dictionary within the settings for a connection, not a single string, and thus the sub-dictionary would need to be dictionary<string, object>.
Similar to flq's answer, here's a more comprehensive solution which makes both subdictionaries:
using System.Collections.Generic;
using System.Linq;
namespace LINQDictionaryDemo
{
public class IPAddress
{
public int Index { get; private set; }
public string Value { get; private set; }
public IPAddress(int Index, string Value)
{
this.Index = Index;
this.Value = Value;
}
}
public class NetworkConnection
{
public string Name { get; set; }
public string ConnectionName { get; set; }
public bool DHCPEnabled { get; set; }
public List<IPAddress> IPAddresses { get; set; }
public Dictionary<string, object> ToDictionary()
{
return new Dictionary<string, object>
{
{ "ConnectionName", ConnectionName }
, { "DHCPEnabled", DHCPEnabled.ToString() }
, {"IPAddresses", IPAddresses.ToDictionary(k => k.Index, v => v.Value)}
};
}
}
public static class Demo
{
public static void Run()
{
var lnc = new List<NetworkConnection>
{
new NetworkConnection
{
Name = "Broadcom",
ConnectionName = "Local Area Connection",
DHCPEnabled = false,
IPAddresses = new List<IPAddress> {new IPAddress(1, "abc.de.fg.h")}
}
};
var dic = lnc.ToDictionary(k => k.Name, v => v.ToDictionary());
}
}
}