Get int value from picker using dictionary - c#

Somebody told me that the key of a dictionary should be unique, so i changed my dictionary from:
Dictionary<string, int> recipients = new Dictionary<string, int>();
to
Dictionary<int, string> recipients = new Dictionary<int, string>();
Because the int is unique in my case, and the string isn't per se.
But first i could get the int from a picker aswell, but now i cant figure it out.
The picker:
pickerRecipients = new Picker
{
};
foreach (string recipientName in recipients.Values)
{
pickerRecipients.Items.Add(recipientName);
}
First i would do
string currentlySelected = pickerRecipients.Items[pickerRecipients.SelectedIndex];
But now it obviously doesnt work, but i can't find a way to get the int (the picker shows the string, which is a name, the int thats connected to it is an unique user number)

// get the key of the first match
var key = recipients.FirstOrDefault(x => x.Value == selectedName).Key;

I don't have enough rep to put it as a comment but your code will have problems. For example if u have this values in your dictionary : '1 someValue', '2 otherValue', '3 someValue' and the user will pick '3 someValue'. Your code will return 1.
I think you could try to insert (I entered a SPACE before the ( so i can split by ' ')
foreach (var recipient in recipients)
{
pickerRecipients.Items.Add(recipient.Value + " (" + recipient.Key + ")");
}
then get the user selected value with
string currentlySelected = pickerRecipients.Items[pickerRecipients.SelectedIndex];
split the result like
var selectedIndex = currentlySelected.Split(' ').Last().Split('(', ')')[1];
and you get your selected index.
Again, this is not a direct solution to your problem but your problem will generate other problems if you don't take this into consideration.

Related

Create a 2-column List using a variable for list name

Because the original post (Create List with name from variable) was so old, I didn't want to approach this as an answer.
But, I wanted to add this use of the above solution because it was non-obvious to me. And, it may help some of my fellow noobs... Also, I ran into some issues I don't know how to address.
I needed a way to create a list using a variable name, in this case "mstrClock", for timing diagrams.
I was not able to get .NET to accept a two-column list, though, so I ended up with two dictionaries.
Is there a way to structure this so that I can use a single dictionary for both columns?
dictD.Add("mstrClock", new List<double>());
dictL.Add("mstrClock", new List<string>());
Then as I develop the timing diagram, I add to the lists as follows:
dictD["mstrClock"].Add(x); // This value will normally be the time value.
dictL["mstrClock"].Add("L"); // This value will be the "L", "F" or "H" logic level
Then to get at the data I did this:
for (int n = 0; n < dictD["mstrClock"].Count; n++)
{
listBox1.Items.Add(dictL["mstrClock"][n] + "\t" + dictD["mstrClock"][n].ToString());
}
Why not just store what you want to display, in the dictionary?
dict.Add("mstrClock", new List<string>());
dict["mstrClock"].Add($"L\t{x}");
for (int n = 0; n < dict["mstrClock"].Count; n++)
{
listBox1.Items.Add(dict["mstrClock"][n]);
}
On another point, do you even need a dictionary? What is the point of having a dictionary with one key? If you only need a List<string>, then only create that.
var items = new List<string>());
items.Add($"L\t{x}");
foreach (var item in items)
{
listBox1.Items.Add(item);
}
You can use Tuples in modern C# to create your two-column list as follows:
var list = new List<(double time, string logicLevel)>();
list.Add((1, "L"));
list.Add((2, "F"));
foreach (var element in list)
{
listBox1.Items.Add($"{element.time} \t {element.logicLevel}");
}
If using a dictionary is a must, you can change the above code to something like:
var dict = new Dictionary<string, List<(double time, string logicLevel)>>();
dict["mstrClock"] = new List<(double time, string logicLevel)>();
dict["mstrClock"].Add((1, "L"));
dict["mstrClock"].Add((2, "F"));
var list = dict["mstrClock"];
foreach (var element in list)
{
listBox1.Items.Add($"{element.time} \t {element.logicLevel}");
}
One approach to creating a 2-column list would be to create a list of key/value pairs:
var list = new List<KeyValuePair<double, string>();
list.Add(new KeyValuePair<double, string>(1, "L");
foreach (KeyValuePair<double, string> element in list)
{
listBox1.Items.Add($"{element.key} \t {element.value}");
}

Chain of objects

I have an object;
class MyObject
{
double Timestamp;
string Originalname;
string Renamedname;
}
I have an array of MyObject
1538148190,"C:\test\jeff.txt","jeffmodified.txt"
1538148200,"C:\test\jeffmodified.txt","jeffmodified2.txt"
1538148289,"C:\test\jeffmodified2.txt","jeffmodified3.txt"
1538149002,"C:\test\thing.txt","something.txt"
I am trying to create a correlation of the data to present the idea that jeff.txt was renamed to jeffmodified.tx and then to jeff.modified2.txt and jeffmodified3.txt. The timestamp (unix format) shows me that jeff.txt was the original file name.
Can this be done in linq? This is working with objects in memory only - not a database and the max number of objects would generally be 200 objects.
Using linq this cannot be done in a one or two liner (if that is what you meant by can this be done in linq. But due to linq the solution does become easier then what it would have been without linq.
The important assumptions that I have made in the solution below is that the timestamp will increase with each file name change. Solution is explained in the comments provided.
static void Main(string[] args)
{
// setting up test data, can be removed from actual solution where objects can be populated as required
List<MyObject> objects = new List<MyObject>();
objects = GetData();
int i = 0;
int key = 0;
List<WrapMyObject> wObjs = new List<WrapMyObject>();
Dictionary<int, string> origDictionary = new Dictionary<int, string>();
Dictionary<int, string> searchDictionary = new Dictionary<int, string>();
// adding the directory path to the renamed filename as well, since same filename can be there for different filepath
Func<string, string> GetFilePath = (path) => path.Substring(0, path.LastIndexOf('\\'));
objects.ForEach(x=>x.Renamedname = GetFilePath(x.Originalname) + "\\" + x.Renamedname);
//sort the whole list by timestamp, this should ensure that we begin always with the orignal file and always get subsequent changed filename in the list
//the algorithm relies on the fact that the renamed name should be the next orignal name for that file change in the sorted list
//if current item's orignal name is not in search dictory then we are seeing this file path first time, add to orignal dictionary with key, add the renamed name in search dictionary with same key
//else add add the search path found in searchDictionary back into origDictionary and update the searchDict with the new path value (current item renamed path)
var sortedObjects = objects.OrderBy(o => o.Timestamp);
foreach (var item in objects)
{
if (searchDictionary.ContainsValue(item.Originalname))
{
key = searchDictionary.Where(x => x.Value == item.Originalname).First().Key;
origDictionary[key] = origDictionary[key] + "!" + searchDictionary[key];
searchDictionary[key] = item.Renamedname;
}
else
{
origDictionary.Add(i, item.Originalname);
searchDictionary.Add(i, item.Renamedname);
}
i++;
}
//iterated the whole list of objects....which means the final node would be remaining in the search dictionary, add them back to origDictionary to complete the modified path
searchDictionary.ToList().ForEach(x => origDictionary[x.Key] = origDictionary[x.Key] + "!" + searchDictionary[x.Key]);
//at this point orgnalDict has the list of all names that each file was modified with.
}

Put picker selected dictionary value in another picker

I'm having struggles with the following:
I have a Dictionary that gets filled by a webAPI.
Dictionary<string, int> recipients = new Dictionary<string, int>();
And i have a picker
pickerRecipients = new Picker
{
};
foreach (string recipientName in recipients.Keys)
{
pickerRecipients.Items.Add(recipientName);
}
What i want is that with the press of a button, the selected value to be put in a second Dictionary
Dictionary<string, int> multiRecipients = new Dictionary<string, int>();
To add it i used
multiRecipients.Add(KEY, VALUE);
But as far as i know, i could only acces the value, and not the key. I have no idea how to do that. I think the main problem is that i select it from a picker, and not directly from the dictionary.
Many thanks to anybody who can enlighten me (:
p.s. I use Xamarin
edit:
This is what i have now, but i also changed the int to a string, and the string to an int.
if (pickerRecipients.SelectedIndex != -1)
{
string currentlySelected = pickerRecipients.Items[pickerRecipients.SelectedIndex];
var SelectedValue = recipients[currentlySelected];
multiRecipients.Add(currentlySelected, SelectedValue);
}
since you already know the key to item, just use the [key] syntax to retrieve the value:
var SelectedValue = recipients[SelectedKey];
multiRecipients.Add(SelectedKey, SelectedValue);
you can use linq to get the key using the value from the dictionary, it would be like:
var key= recipients.FirstOrDefault(x => x.Value == selectedValue).Key;
multiRecipients.Add(key,selectedValue);

Dictionary<int, List<string>>

I have something like this:
Dictionary<int, List<string>> fileList = new Dictionary<int, List<string>>();
and then, I fill it with some variables, for example:
fileList.Add(
counter,
new List<string> {
OFD.SafeFileName,
OFD.FileName,
VERSION, NAME , DATE ,
BOX , SERIAL_NUM, SERIES,
POINT , NOTE , VARIANT
}
);
Where counter is a variable that increment +1 each time something happens, List<string>{XXX} where XXX are string variables that holds some text.
My question is, how do I access these strings from the list, if counter == 1?
You can access the data in the dictionary and lists just like normal. Remember, access a value in the dictionary first, which will return a list. Then, access the items in the list.
For example, you can index into the dictionary, which returns a list, and then index into the list:
------ Returns a list from the dictionary
| --- Returns an item from the list
| |
v v
fileList[0][0] // First item in the first list
fileList[1][0] // First item in the second list
fileList[1][1] // Second item in the second list
// etc.
FishBasketGordo explains how you can access entries in your data structure. I will only add some thoughts here:
Dictionaries (based on hash tables) allow fast access to arbitrary keys. But your keys are given by a counter variable (counter = 0, 1, 2, 3, 4 ...). The fastest way to access such keys is to simply use the index of an array or of a list. Therefore I would just use a List<> instead of a Dictionary<,>.
Furthermore, your list seems not to list anonymous values but rather values having very specific and distinct meanings. I.e. a date is not the same as a name. In this case I would create a class that stores these values and that allows an individual access to individual values.
public class FileInformation
{
public string SafeFileName { get; set; }
public string FileName { get; set; }
public decimal Version { get; set; }
public string Name { get; set; }
public DateTime Date { get; set; }
...
}
Now you can create a list like this:
var fileList = new List<FileInformation>();
fileList.Add(
new FileInformation {
SafeFileName = "MyDocument.txt",
FileName = "MyDocument.txt",
Version = 1.2,
...
}
}
And you can access the information like this
decimal version = fileList[5].Version;
If the keys don't start at zero, just subtract the starting value:
int firstKey = 100;
int requestedKey = 117;
decimal version = fileList[requestedKey - firstKey].Version;
Dictionary uses Indexer to access its vallues via key.
List<string> items = fileList[counter];
var str0 = items[0];
var str1 = items[1];
Then you can do anything with the list.
Dictionary<int, List<string>> fileList = new Dictionary<int, List<string>>();
fileList.Add(101, new List<string> { "fijo", "Frigy" });
fileList.Add(102, new List<string> { "lijo", "liji" });
fileList.Add(103, new List<string> { "vimal", "vilma" });
for (int Key = 101; Key < 104; Key++)
{
for (int ListIndex = 0; ListIndex < fileList[Key].Count; ListIndex++)
{
Console.WriteLine(fileList[Key][ListIndex] as string);
}
}
You can access the List through MyDic[Key][0]. While editing the list, there won't be any run time errors, however it will result in unnecessary values stored in Dictionary. So better:
assign the MyDict[Key] to new list
edit the new list and then
reassign the new list to MyDict[Key] rather than editing a
particular variable in the Dictionary with List as Values.
Code example:
List<string> lstr = new List<string(MyDict[Key]);
lstr[0] = "new Values";
lstr[1] = "new Value 2";
MyDict[Key] = lstr;

get unique values from query to build Dictionary

I want to build a combobox with key->postal and value->city to use as filter for my accomodations.
To limit the number of items in the list I only use the postals I have used when filling up the table tblAccomodations.
For now I do not use a relational table with postals and city's although I'm thinking about an update later on.
Here I build my dictionary:
public static Dictionary<int, string> getPostals()
{
Dictionary<int, string> oPostals = new Dictionary<int, string>();
using (DBReservationDataContext oReservation = new DBReservationDataContext())
{
var oAllPostals = (from oAccomodation in oReservation.tblAccomodations
orderby oAccomodation.Name ascending
select oAccomodation);
foreach (tblAccomodation item in oAllPostals)
{
oPostals.Add(int.Parse(item.Postal), item.City);
}
}
return oPostals;
}
As expected I got an error: some Accomodations are located in the same city, so there are double values for the key. So how can I get a list of unique cities and postals (as key)?
I tried to use
select oAccomodation.Postal.Distinct()
but that didn't work either.
UPDATE: I have found the main problem. There are multiple cities with the same postal ("Subcity"). So I'm gonna filter on "City" and not on "Postal".
I think your looking for 'Distinct'. Gather your list of all postals and then return myPostals.Distinct().
Hope than helps.
change
foreach (tblAccomodation item in oAllPostals)
{
oPostals.Add(int.Parse(item.Postal), item.City);
}
to
foreach (tblAccomodation item in oAllPostals.Distinct(x=>x..Postal)
{
if(!oPostals.ContainsKey(int.Parse(item.Postal)))
oPostals.Add(int.Parse(item.Postal), item.City);
}
BTW, if you have multiple cities in one postal (I am not sure if it is possible in your domain), which one you want to see?
If any of cities will do, then it is easy to just get the first one per postal:
var oAllPostals = oReservation.tblAccomodations
.OrderBy(x=>x.Name)
.ToLookup(x=>x.Postal, x=>x.City)
.ToDictionary(x=>x.Key, x.First());
In the same example if you do .ToList() or even .Distinct().ToList() instead of .First() you will have all of cities in the dictionary of Dictionary<Postal, List<City>>.
Assuming the combination of postal + city is unique you could do the following:
public static Dictionary<int, string> getPostals()
{
Dictionary<int, string> oPostals = new Dictionary<int, string>();
using (DBReservationDataContext oReservation = new DBReservationDataContext())
{
var oAllPostals = (from oAccomodation in oReservation.tblAccomodations
orderby oAccomodation.Name ascending
select oAccomodation);
foreach (tblAccomodation item in oAllPostals)
{
oPostals.Add((item.Postal + item.City).GetHashCode(), item.Postal + " " + item.City);
}
}
return oPostals;
}
Edit:
If you want to use the selected value from the drop box then you can use the following:
public static Dictionary<int, Tuple<string, string>> getPostals()
{
Dictionary<int, string> oPostals = new Dictionary<int, string>();
using (DBReservationDataContext oReservation = new DBReservationDataContext())
{
var oAllPostals = (from oAccomodation in oReservation.tblAccomodations
orderby oAccomodation.Name ascending
select oAccomodation);
foreach (tblAccomodation item in oAllPostals)
{
oPostals.Add((item.Postal + item.City).GetHashCode(), new Tuple<string, string>(item.Postal, item.City));
}
}
return oPostals;
}
The way you bind the following depends on whether you're using asp.net, winforms etc. Here's an example for winforms.
Using .containkey will exclude [1 (postal key) to n (cities relation)]. i.e since Key already exists next city (with the same postal key ) will not get into your dictionary.
However, if you want to map your postal to list of cities, you can represent a dictionary that can contain a collection of values like the following:
Dictionary < String[Postal]> , List < Cities>>
This way you'll have a dictionary that can have multiple values.

Categories

Resources