How to get item from dictionary by value of property - c#

I have a Dictionary<string, User>.
User is an object with the properties UID, UNIQUE KEY and more. My dictionary key is the UNIQUE KEY of the users.
Now, i want to get a User from my dictionary values by a UID and not the key, something like ContainsKey.. how its done with lambda expr or linq? is there a good solution for that?

Here's a working sample:
using System;
using System.Collections.Generic;
using System.Linq;
internal class User
{
public string ID { get; set; }
public string Name { get; set; }
}
internal class Program
{
private static void Main(string[] args)
{
Dictionary<string, User> dic = new Dictionary<string, User>();
dic.Add("1", new User { ID = "id1", Name = "name1" });
dic.Add("2", new User { ID = "id2", Name = "name2" });
dic.Add("3", new User { ID = "id3", Name = "name3" });
User user = dic.Where(z => z.Value.ID == "id2").FirstOrDefault().Value;
Console.ReadKey();
}
}

return dict.Single(x => x.Value.UID == target);
Of course, you might find that your design is questionable if it involves continually doing linear searches across a Dictionary.

Of course you'll loose the benefit of having a dictionary, but you can do someting like:
var user = dict.Values.FirstOrDefault(k=>k.UID==xxxx);

This should get the user for the UID from the dictionary:
public User GetUserForUid(Dictionary<string, User> dictionary, int uid)
{
return dictionary.Values.FirstOrDefault(u => u.UID == uid);
}

Related

Compare Object vs Dictionary<int,List<int>> considering performance c#

using System;
using System.Collections.Generic;
using System.Linq;
namespace ConsoleApp5
{
class Validator
{
static void Main()
{
var metaValues = new List<Meta>
{
new Meta(4, 15, true),
new Meta(5, 20, false)
};
var requestDict = new Dictionary<int, List<int>>
{
{4, new List<int>{15,20} },// error not exist
{5, new List<int>{25} }, // error its false
{6, new List<int>{30} } // error not exist
};
var matchedIds = new List<int>();
if (metaValues.Any())
{
foreach (var ob in metaValues)
{
if (requestDict.ContainsKey(ob.Id))
{
matchedIds.Add(ob.Id);
var valuesDict = requestDict[ob.Id];
//here i cant get all the values and its Active of meta.Id
}
}
}
foreach (var key in requestDict.Keys)
{
if (!matchedIds.Contains(key))
Console.WriteLine("Invalid");
}
}
}
public class Meta
{
public int Id { get; private set; }
public int Value { get; private set; }
public bool IsActive { get; private set; }
public Meta(int id, int value, bool isActive)
{
Id = id;
Value = value;
IsActive = isActive;
}
}
}
iterating dictionary with object causing performance issue since everytime dictionary key has to be iterated in an list of object so i am trying to take object and lookup in dictionary on below condition
Invalid when meta.Id does not exist in dictionary key
Invalid when one of the meta.Value does not exist in dictionary values List
Inactive when meta.Id and meta.value match with dictionary but meta.isactive is false
I probably shouldn't bother answering since:
The code is quite messy
It does not compile
The question is very unclear
However, for some reason I feel like I understand a little what you're trying to do and wanted to provide some help.
First, let's NOT name a class with the same name as a built-in type (System.Object). Perhaps Item is generic enough? Also, you appear to instantiate instances of this class by calling a constructor that doesn't exist, so let's add that constructor as well:
public class Item
{
public int Id { get; }
public int Value { get; }
public bool IsActive { get; }
public Item(int id, int value, bool isActive)
{
Id = id;
Value = value;
IsActive = isActive;
}
}
Now we can create our list of Item objects by calling the constructor:
var items = new List<Item>
{
new Item(4, 15, true),
new Item(5, 20, false)
};
It also appears that you're creating a dictionary that contains a Key of type int that maps to Item.Id, and a Value of type List<int> that sort-of maps to Item.Value (though Item.Value is a single int). A problem in the code you posted is that you're trying to add two items with the same Key value of 4, which is not legal for a Dictionary - all the keys must be unique. To fix this, I'm using unique keys:
var requests = new Dictionary<int, List<int>>
{
{4, new List<int> {15}},
{5, new List<int> {20}},
{6, new List<int> {25}},
{7, new List<int> {30}}
};
Next it appears that you're trying to create a List<int> of numbers representing the Item.Id values that exist as dictionary keys. This can be done with a System.Linq extension method:
var matchedIds = items
.Where(item => requests.ContainsKey(item.Id))
.ToList();
And finally, it's not exactly clear what you want to do with this list, but it appears you want to do something if either an Item.Id does not exist in the dictionary, or the Item.Id exists but the Item.Value is not in the list, or the item does exist, but the Item.IsActive value is false, or some other combination of these properties.
Here's how to get those items:
var matchedIds = items
.Where(item => requests.ContainsKey(item.Id))
.ToList();
var matchedIdsAndValues = matchedIds
.Where(item => requests[item.Id].Contains(item.Value))
.ToList();
var matchedIdsMissingValue = matchedIds
.Where(item => !requests[item.Id].Contains(item.Value))
.ToList();
var unmatchedIds = items
.Where(item => !requests.ContainsKey(item.Id))
.ToList();
var matchedIdAndValueButNotActive = matchedIdsAndValues
.Where(item => !item.IsActive)
.ToList();
Hope this helps!

Getting a value from a ConcurrentDictionary

If I have this ConcurrentDictionary:
public class User
{
public string Context { get; set; }
public bool Owner { get; set; }
}
protected static ConcurrentDictionary<User, string> OnlineUsers = new ConcurrentDictionary<User, string>();
Does anyone know how I would get the value of Owner if I already have the value of the Context? Basically I want to do a "find" using the Context. Thanks.
Does anything stop you from using standard Linq FirstOrDefault() method like so:
var item = OnlineUsers.FirstOrDefault(kvp => kvp.Key.Context == myContext);
How obout something like
var ou = OnlineUsers.First(x => x.Key.Context == "TADA");
It sounds like you need a Dictionary<string, User> which, when given the context as a string will tell you which User it corresponds to. If you are going to need to perform this lookup several times, and there isn't a problem using the additional memory, it may be worth creating such a dictionary.
If you are only going to be doing the search once or twice, or the mappings will be changing so often that you can't keep the dictionary up to date, then you can simply do a linear search on the dictionary using a foreach loop, or using a LINQ method such as First or Where, as demonstrated in other answers.
Here you go:
ConcurrentDictionary<User, string> dict = new ConcurrentDictionary<User, string>();
dict.TryAdd(new User() { Context = "a", Ownder = false }, "aa");
dict.TryAdd(new User() { Context = "b", Ownder = false }, "bb");
dict.TryAdd(new User() { Context = "c", Ownder = true }, "cc");
dict.TryAdd(new User() { Context = "d", Ownder = false }, "dd");
IEnumerable<User> list = dict.Keys.Where(p => p.Context == "a");

Dictionary with two keys?

I am keeping track of values in a console. Two people "duel" against each other and I was using a dictionary to keep the names recorded along with damage done.
var duels = new Dictionary<string, string>();
duels.Add("User1", "50");
duels.Add("User2","34");
I'm trying to store both users in the same dictionary row, so it could be verified as User1 is dueling against User2. This way if another duel started, it would not interfere with User1 or User2.
duels.Add("KeyUser1","KeyUser2","50","34",.../*Other attributes of the duel*/);
I need two keys so I can check where the user's damage will go. The damage will always go to the other key--vice versa.
What can I do to make this work?
Thank you.
public class Duel
{
public string User1 {get; protected set;}
public string User2 {get; protected set;}
public Duel(string user1, string user2)
{
User1 = user1;
User2 = user2;
}
public HashSet<string> GetUserSet()
{
HashSet<string> result = new HashSet<string>();
result.Add(this.User1);
result.Add(this.User2);
return result;
}
//TODO ... more impl
}
Let's make some duels. CreateSetComparer allows the dictionary to use the values of the set for equality testing.
List<Duel> duelSource = GetDuels();
Dictionary<HashSet<string>, Duel> duels =
new Dictionary<HashSet<string>, Duel>(HashSet<string>.CreateSetComparer());
foreach(Duel d in duelSource)
{
duels.Add(d.GetUserSet(), d);
}
And finding a duel:
HashSet<string> key = new HashSet<string>();
key.Add("User1");
key.Add("User2");
Duel myDuel = duels[key];
You could try making a custom data type for the key:
class DualKey<T> : IEquatable<DualKey<T>> where T : IEquatable<T>
{
public T Key0 { get; set; }
public T Key1 { get; set; }
public DualKey(T key0, T key1)
{
Key0 = key0;
Key1 = key1;
}
public override int GetHashCode()
{
return Key0.GetHashCode() ^ Key1.GetHashCode();
}
public bool Equals(DualKey<T> obj)
{
return (this.Key0.Equals(obj.Key0) && this.Key1.Equals(obj.Key1))
|| (this.Key0.Equals(obj.Key1) && this.Key0.Equals(obj.Key0));
}
}
Then use a Dictionary<DualKey<string>, string>;
Something quick.
class UserScores {
public string Key { get; set; }
public int User1Score { get; set; }
public int User2Score { get; set; }
public UserScores(string username1, string username2)
{
Key = username1 + ":" + username2;
}
}
void Main()
{
var userScore = new UserScores("fooUser", "barUser");
var scores = new Dictionary<string, UserScores>();
scores.Add(userScore.Key, userScore);
// Or use a list
var list = new List<UserScores>();
list.Add(userScore);
list.Single (l => l.Key == userScore.Key);
}
Although a proper solution in my opinion would use a better thought out UserScores object that tracks that particular "duel" session.
Since a single person can be involved in at most one duel at a time, you can use a single dictionary to directly "index" both endpoints in all duels, something like this:
class Duel {
public Duel(string user1, string user2) {
Debug.Assert(user1 != user2);
User1 = user1;
User2 = user2;
}
public readonly string User1;
public readonly string User2;
public int User1Score;
public int User2Score;
}
class Program {
static void Main(string[] args) {
var dict = new Dictionary<string, Duel>();
// Add a new duel. A single duel has two keys in the dictionary, one for each "endpoint".
var duel = new Duel("Jon", "Rob");
dict.Add(duel.User1, duel);
dict.Add(duel.User2, duel);
// Find Jon's score, without knowing in advance whether Jon is User1 or User2:
var jons_duel = dict["Jon"];
if (jons_duel.User1 == "Jon") {
// Use jons_duel.User1Score.
}
else {
// Use jons_duel.User2Score.
}
// You can just as easily find Rob's score:
var robs_duel = dict["Rob"];
if (robs_duel.User1 == "Rob") {
// Use robs_duel.User1Score.
}
else {
// Use robs_duel.User2Score.
}
// You are unsure whether Nick is currently duelling:
if (dict.ContainsKey("Nick")) {
// Yup!
}
else {
// Nope.
}
// If Jon tries to engage in another duel while still duelling Rob:
var duel2 = new Duel("Jon", "Nick");
dict.Add(duel2.User1, duel); // Exception! Jon cannot be engaged in more than 1 duel at a time.
dict.Add(duel2.User2, duel); // NOTE: If exception happens here instead of above, don't forget remove User1 from the dictionary.
// Removing the duel requires removing both endpoints from the dictionary:
dict.Remove(jons_duel.User1);
dict.Remove(jons_duel.User2);
// Etc...
}
}
This is just a basic idea, you might consider wrapping this functionality in your own class...

Refactoring two lists of strings

I have two lists of strings. One is object friendly name and other one is object class name.
"Car","Animal","Plane"
"MachineClass","AnimalClass","FlyClass".
I use friendly names to show user input and class names to dynamically create class instances by using reflection, so i need both lists and like you can see "Car" as friendly name can be bound to "Machine.cs".
I need some more creative way of working and translating both of these lists rather than using switch statement which converts from one string to other, those lists have numerous items and i can make small spelling which will cause error. Moreover sometimes, i send string of test name for evaluation whereas same problem with spellings can apply there.
I tried to think about using enums but still digits doesn't ring a bell for conversions between both lists.
public enum Things
{
Car,
Animal,
Plane
}
var dict = new Dictionary<Things, string> {
{ Things.Car, "MachineClass" },
{ Things.Animal, "AnimalClass" },
{ Things.Plane, "FlyClass" } };
string classname = dict[Things.Plane]; // FlyClass
Now if you wanted real types, that you can instantiate:
var realtypes = dict.ToDictionary(
kvp => kvp.Key,
kvp => System.Type.GetType("Namespace." + kvp.Value));
A fully working example is on http://ideone.com/TTuBP:
using System;
using System.Collections.Generic;
using System.Linq;
//public interface IThing {}
public class MachineClass /* : IThing */ { }
public class AnimalClass /* : IThing */ { }
public class Plane /* : IThing */ { }
public class Program
{
public enum Things
{
Car,
Animal,
Plane
}
private static readonly IDictionary<Things, string> _classNameMap =
new Dictionary<Things, string> {
{ Things.Car, "MachineClass" },
{ Things.Animal, "AnimalClass" },
{ Things.Plane, "FlyClass" } };
public static void Main(string[] args)
{
var realtypes = _classNameMap.ToDictionary(
kvp => kvp.Key,
kvp => System.Type.GetType(/*"Namespace." +*/ kvp.Value));
Type dynamicType = realtypes[Things.Plane]; // typeof(Namespace.FlyClass)
foreach (var realtype in realtypes)
Console.WriteLine("{0}, class {1}",
realtype.Key, realtype.Value);
}
}
Why not use a dictionary?
Dictionary<string, string> classMap_ = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
classMap_["Car"] = "MachineClass";
classMap_["Animal"] = "AnimalClass";
classMap_["Plane"] = "FlyClass":
Creating the appropriate class is as simple as:
string className = classMap_["Car"];
Use maps HashMap to maintain friendly name and class name mapping
I don't recomend to use reflection for creation objects of classes from performance point of view, insteed you can use lambda expressions to create objects
look at the following code
var animals = new Dictionary<string, Func<object>>
{
{"Animal 1", () => new MyAnimal1()},
{"Animal 2", () => new MyAnimal2()}
};
var createAnimal = animals["Animal 1"];
var animal = createAnimal();
where
private class MyAnimal1
{
}
private class MyAnimal2
{
}
insteed this classes you should use your classes.
Why not using databinding?
class Wrapper
{
public string UserFriendly{get;set;}
public string Technical{get;set;}
}
var data = new[]
{
new Wrapper("Car", "MachineClass"),
new Wrapper("Plane", "FlyClass"),
};
combo.Datasource = data;
combo.DisplayMember = "UserFriendly";
combo.ValueMember = "Technical";
Combo will display the friendlyname but when asking for SelectedValue you will get the technical name.

How to compare two distinctly different objects with similar properties

This is all in C#, using .NET 2.0.
I have two lists of objects. They are not related objects, but they do have certain things in common that can be compared, such as a GUID-based unique identifier. These two lists need to be filtered by another list which just contains GUIDs which may or may not match up with the IDs contained in the first two lists.
I have thought about the idea of casting each object list to just object and sorting by that, but I'm not sure that I'll be able to access the ID property once it's cast, and I'm thinking that the method to sort the two lists should be somewhat dumb in knowing what the list to be sorted is.
What would be the best way to bring in each object list so that it can be sorted against the list with only the IDs?
You should make each of your different objects implement a common interface. Then create an IComparer<T> for that interface and use it in your sort.
Okay, if you have access to modify your original classes only to add the interface there, Matthew had it spot on. I went a little crazy here and defined out a full solution using 2.0 anonymous delegates. (I think I'm way addicted to 3.0 Lambda; otherwise, I probably would've written this out in foreach loops if I was using 2005 still).
Basically, create an interface with the common properties. Make yoru two classes implement the interface. Create a common list casted as the interface, cast and rip the values into the new list; remove any unmatched items.
//Program Output:
List1:
206aa77c-8259-428b-a4a0-0e005d8b016c
64f71cc9-596d-4cb8-9eb3-35da3b96f583
List2:
10382452-a7fe-4307-ae4c-41580dc69146
97f3f3f6-6e64-4109-9737-cb72280bc112
64f71cc9-596d-4cb8-9eb3-35da3b96f583
Matches:
64f71cc9-596d-4cb8-9eb3-35da3b96f583
Press any key to continue . . .
using System;
using System.Collections.Generic;
using System.Text;
namespace ConsoleApplication8
{
class Program
{
static void Main(string[] args)
{
//test initialization
List<ClassTypeA> list1 = new List<ClassTypeA>();
List<ClassTypeB> list2 = new List<ClassTypeB>();
ClassTypeA citem = new ClassTypeA();
ClassTypeB citem2 = new ClassTypeB();
citem2.ID = citem.ID;
list1.Add(new ClassTypeA());
list1.Add(citem);
list2.Add(new ClassTypeB());
list2.Add(new ClassTypeB());
list2.Add(citem2);
//new common list.
List<ICommonTypeMakeUpYourOwnName> common_list =
new List<ICommonTypeMakeUpYourOwnName>();
//in english, give me everything in list 1
//and cast it to the interface
common_list.AddRange(
list1.ConvertAll<ICommonTypeMakeUpYourOwnName>(delegate(
ClassTypeA x) { return (ICommonTypeMakeUpYourOwnName)x; }));
//in english, give me all the items in the
//common list that don't exist in list2 and remove them.
common_list.RemoveAll(delegate(ICommonTypeMakeUpYourOwnName x)
{ return list2.Find(delegate(ClassTypeB y)
{return y.ID == x.ID;}) == null; });
//show list1
Console.WriteLine("List1:");
foreach (ClassTypeA item in list1)
{
Console.WriteLine(item.ID);
}
//show list2
Console.WriteLine("\nList2:");
foreach (ClassTypeB item in list2)
{
Console.WriteLine(item.ID);
}
//show the common items
Console.WriteLine("\nMatches:");
foreach (ICommonTypeMakeUpYourOwnName item in common_list)
{
Console.WriteLine(item.ID);
}
}
}
interface ICommonTypeMakeUpYourOwnName
{
Guid ID { get; set; }
}
class ClassTypeA : ICommonTypeMakeUpYourOwnName
{
Guid _ID;
public Guid ID {get { return _ID; } set { _ID = value;}}
int _Stuff1;
public int Stuff1 {get { return _Stuff1; } set { _Stuff1 = value;}}
string _Stuff2;
public string Stuff2 {get { return _Stuff2; } set { _Stuff2 = value;}}
public ClassTypeA()
{
this.ID = Guid.NewGuid();
}
}
class ClassTypeB : ICommonTypeMakeUpYourOwnName
{
Guid _ID;
public Guid ID {get { return _ID; } set { _ID = value;}}
int _Stuff3;
public int Stuff3 {get { return _Stuff3; } set { _Stuff3 = value;}}
string _Stuff4;
public string Stuff4 {get { return _Stuff4; } set { _Stuff4 = value;}}
public ClassTypeB()
{
this.ID = Guid.NewGuid();
}
}
}
Using only .NET 2.0 methods:
class Foo
{
public Guid Guid { get; }
}
List<Foo> GetFooSubset(List<Foo> foos, List<Guid> guids)
{
return foos.FindAll(foo => guids.Contains(foo.Guid));
}
If your classes don't implement a common interface, you'll have to implement GetFooSubset for each type individually.
I'm not sure that I fully understand what you want, but you can use linq to select out the matching items from the lists as well as sorting them. Here is a simple example where the values from one list are filtered on another and sorted.
List<int> itemList = new List<int>() { 9,6,3,4,5,2,7,8,1 };
List<int> filterList = new List<int>() { 2, 6, 9 };
IEnumerable<int> filtered = itemList.SelectMany(item => filterList.Where(filter => filter == item)).OrderBy(p => p);
I haven't had a chance to use AutoMapper yet, but from what you describe you wish to check it out. From Jimmy Bogard's post:
AutoMapper conventions
Since AutoMapper flattens, it will
look for:
Matching property names
Nested property names (Product.Name
maps to ProductName, by assuming a
PascalCase naming convention)
Methods starting with the word “Get”,
so GetTotal() maps to Total
Any existing type map already
configured
Basically, if you removed all the
“dots” and “Gets”, AutoMapper will
match property names. Right now,
AutoMapper does not fail on mismatched
types, but for some other reasons.
I am not totally sure what you want as your end results, however....
If you are comparing the properties on two different types you could project the property names and corresponding values into two dictionaries. And with that information do some sort of sorting/difference of the property values.
Guid newGuid = Guid.NewGuid();
var classA = new ClassA{Id = newGuid};
var classB = new ClassB{Id = newGuid};
PropertyInfo[] classAProperties = classA.GetType().GetProperties();
Dictionary<string, object> classAPropertyValue = classAProperties.ToDictionary(pName => pName.Name,
pValue =>
pValue.GetValue(classA, null));
PropertyInfo[] classBProperties = classB.GetType().GetProperties();
Dictionary<string, object> classBPropetyValue = classBProperties.ToDictionary(pName => pName.Name,
pValue =>
pValue.GetValue(classB, null));
internal class ClassB
{
public Guid Id { get; set; }
}
internal class ClassA
{
public Guid Id { get; set; }
}
classAPropertyValue
Count = 1
[0]: {[Id, d0093d33-a59b-4537-bde9-67db324cf7f6]}
classBPropetyValue
Count = 1
[0]: {[Id, d0093d33-a59b-4537-bde9-67db324cf7f6]}
Thist should essentially get you what you want - but you may be better of using linq
class T1
{
public T1(Guid g, string n) { Guid = g; MyName = n; }
public Guid Guid { get; set; }
public string MyName { get; set; }
}
class T2
{
public T2(Guid g, string n) { ID = g; Name = n; }
public Guid ID { get; set; }
public string Name { get; set; }
}
class Test
{
public void Run()
{
Guid G1 = Guid.NewGuid();
Guid G2 = Guid.NewGuid();
Guid G3 = Guid.NewGuid();
List<T1> t1s = new List<T1>() {
new T1(G1, "one"),
new T1(G2, "two"),
new T1(G3, "three")
};
List<Guid> filter = new List<Guid>() { G2, G3};
List<T1> filteredValues1 = t1s.FindAll(delegate(T1 item)
{
return filter.Contains(item.Guid);
});
List<T1> filteredValues2 = t1s.FindAll(o1 => filter.Contains(o1.Guid));
}
}

Categories

Resources