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.
Related
I have a List that contains 2 properties per object. The properties are as follows:
string Project;
double Value;
So in any given case we might have a List of 5 objects, where 3 of them have a Project property called "Test" and the other 2 objects have a Project Property called "Others", but none of the 5 objects have the same "Value".
{
Project = "Test" Value = 1,
Project = "Test" Value = 5,
Project = "Test" Value = 25,
Project = "Others" Value = 89,
Project = "Others" Value = 151
}
Okay, I get a lot of data from a Database (I "Query" it out into a List of objects), then I take the specific properties I need from that List and add to my own List as follows.
public class Data
{
public string Project {get; set;}
public double Value {get; set;}
}
public List<Data> dataList = new List<Data>();
foreach(var item in DatabaseList)
{
Data newData = new Data(
data.Project = item.Project;
data.Value = item.Project;
dataList.Add(newData);
}
This gives me my list of data that I somehow need to combine based on the property in "Project"
But I have a hard time figuring out how to seperate them from one another, my first thought was to find "Unique" "Projects" and adding that to a new List called "counter", to then loop through that list based of the "Project" property, so something like this:
List<Data> counter = dataList.GroupBy(x => x.Project).Select(First()).ToList();
foreach(var item in counter)
{
Data finalItem = new Data();
foreach (var item2 in dataList)
{
if(item.Project == item2.Project)
{
finalItem.Project = item2.Project;
finalItem.Value += item2.Value;
finalList.Add(finalItem);
}
}
}
So I already know that the above is so messy its crazy, and its also not going to work, but this was the angle I was trying to take, I was also thinking whether I could maybe make use of Dictionary, but I feel like there is probably a super simple solution to something like this.
I think your initial thoughts regarding making use of a dictionary are good. Your use of .GroupBy() is a first step to create that dictionary, where the project name is the dictionary Key and the sum of values for that project is the dictionary Value.
You already seem to be familiar with the System.Linq namespace. The extension method .ToDictionary() exists in the same namespace, and can be used to define the Key and Value selector for each KeyValuePair (KVP) in the dictionary as follows:
.ToDictionary(
<selector for Key>,
<selector for Value>
);
The dictionary may be created by utilizing .ToDictionary() directly after .GroupBy(), as follows:
Dictionary<string, double> dataDictionary = dataList
.GroupBy(item => item.Project)
.ToDictionary(
itemsByProject => itemsByProject.Key,
itemsByProject => itemsByProject.Sum(item => item.Value));
Example fiddle here.
You can use the following code to compute the total Value for objects with Project="Test" :
double TestsValue = my_list.Where(o=>o.Project=="Test").Sum(t=>t.Value);
and do the same for "Others".
Assuming you're happy to return an IEnumerable of Data, you can do this:
var projects = dataList.GroupBy(p => p.Project)
.Select(grp =>
new Data
{
Project = grp.First().Project,
Value = grp.Sum(pr => pr.Value)
});
I have 2 lists below:
// From Below List I want to retrieve it Text of each plan like: foreach(var plan in AvailablePlanNames) and then use plan.Text property.
private IList<IWebElement> AvailablePlanNames =>
_webDriver.FindElementsWithWait(By.XPath("//div[#class='asc-checkbox-group']"));
// From Below list I am going to pull 2 properties like:
foreach(var planDetail in PlanDetails), fetch:
planDetail.GetAttribute("id") and planDetail.GetAttribute("checked")
private IList<IWebElement> PlansDetails => _webDriver.FindElementsWithWait(By.XPath("//div[#class='asc-checkbox-group']/input"));
So first list has: ["Plan A", "Plan B", "Plan C"]
Second list can be: [[Plan A ID , true], [Plan B ID, false], [Plan C ID, null]]
I am trying to make a single list of it like Tuple which will have:
Tuple((Plan A, Plan A ID, true), (Plan B, Plan B ID, false), (Plan C, Plan C ID, null))
I searched several posts and tried multiple solutions but did not get it working.
public IList<string> GetAvailablePlans()
{
var list = new List<(string Text, string, string)>();
foreach (var planName in AvailablePlanNames)
{
foreach (var planDetail in PlansDetails)
{
list.Add((planName.Text,
planDetail.GetAttribute("id"),
planDetail.GetAttribute("checked")));
}
}
return (IList<string>)list;
}
Something like this? This code assumes that PlansDetails[i] is corresponding to the AvailablePlanNames[i] for specified i. If this is not true, you will also need to find corresponding data in PlansDetails for each AvailablePlanNames[i].
The code also use correct return value (list of tuples instead of list of strings).
public List<(string Text, string, bool)> GetAvailablePlans()
{
var list = new List<(string Text, string, string)>();
for (var i; i<AvailablePlanNames.Length;i++)
{
list.Add((AvailablePlanNames[i].Text,
PlansDetails[i].GetAttribute("id"),
PlansDetails[i].GetAttribute("checked")));
}
return list;
}
Instead of looping, you can use LINQ's Zip to combine items from two IEnumerable<T>s. :
var results=AvailablePlanNames
.Zip(PlanDetails)
.Select((first,second)=>
( Text: first.Text,
Id: second.GetAttribute("id"),
Check:second.GetAttrbute("checked")
))
.ToList();
I have (for certain reasons not to get into now...) a List of the following structure:
List1<Dictionary1<string, List2<Dictionary2<string, string>>>>
(I added the 1 and 2 naming for clarity).
I want to iterate over List1 and sum up Dictionary1, so that all values of identical keys in Dictionary2 will add up.
For example if each Dictionary1 item contains a Dictionary2:
{ "Price", 23},
{ "Customers", 3}
then I want to iterate over all List2 elements, and over all List1 elements, and have a final dictionary of the total sum of all prices and customers as a single key for each category:
{ "Price", 15235},
{ "Customers", 236}
I hope that's clear.. In other words, I want to sum up this double-nested list in a way that I'm left with all unique keys across all nested dictionaries and have the values summed up.
I believe it can be done with LINQ, but I'm not sure how to do that..
This may be the ugliest thing I've ever written, and makes some assumptions on what you're doing, but I think this gets you what you want:
var query = from outerDictionary in x
from listOfDictionaries in outerDictionary.Values
from innerDictionary in listOfDictionaries
from keyValuePairs in innerDictionary
group keyValuePairs by keyValuePairs.Key into finalGroup
select new
{
Key = finalGroup.Key,
Sum = finalGroup.Sum(a => Convert.ToInt32(a.Value))
};
Where x is your main List.
Ok, so it looks like that you were attempting to create an Dictionary of Items with various properties (Cost, Customers, etc...), which begs the question: why not just create a class?
After all, it would be pretty simple to turn your dictionary of dictionary of items into a single dictionary of properties, such as below.
public class ItemProperties
{
public double Price {get; set;} = 0;
public int Customers {get; set;} = 0;
//Whichever other properties you were thinking of using.
}
static ItemProperties AddAll(Dictionary<string, ItemProperties> items)
ItemProperties finalitem = new ItemProperties();
{
foreach (var item in items)
{
finalitem.Price += item.Price;
finalitem.Customers += item.Customers;
//Repeat for all other existing properties.
}
return finalitem;
}
Of course, this only works if the number and kind of properties is immutable. Another way to approach this problem would be to use TryParse to find properties in Dictionary2 that you think can be added. This is problematic however, and requires some good error checking.
static Dictionary < string, string > AddNestedDictionary(Dictionary < string, Dictionary < string, string > items) {
Dictionary < string, string > finalitem = new Dictionary < string, string > ();
foreach(var item in items) {
foreach(var prop in item) {
if (!finalitem.ContainsKey(prop.Key)) {
finalitem.Add(prop);
}
double i = 0;
if (Double.TryParse(prop.Value, out i)) {
finalitem[prop.Key] += i;
}
}
}
return finalitem;
}
Again, not the best answer compared to the simplicity of a static class. But that would be the price you pay for nonclarity.
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);
I'm trying to retrieve a dataset from RavenDB, group it by several categories and then store it per group in a dictionary. The retrieval and groupby have been solved. However, I'm stuck on how to put the combined group (group on 4 variables) into a dictionary. So in other words: the dictionary needs to be filled with each distinct name/year/month/day combination. I need this to later on display it in a graph - that part is already covered.
Dictionary<string, int> chartInformation = new Dictionary<string, int>();
List<string> xAxisCategories = new List<string>();
if (model.Period.Value == Timespan.Day)
{
var groupedRecords = transformedRecords.GroupBy(x => new
{
x.Name,
x.DateTo.Value.Year,
x.DateTo.Value.Month,
x.DateTo.Value.Day
});
foreach (var recordGroup in groupedRecords)
{
if (!chartInformation.ContainsKey(recordGroup.Key.Name,
recordGroup.Key.Year, recordGroup.Key.Month, recordGroup.Key.Day))
// how to do this properly
{
chartInformation.Add(recordGroup.Key.?, 0);
}
if (!xAxisCategories.Contains(recordGroup.Key.?))
{
xAxisCategories.Add(recordGroup.Key.?);
}
foreach (var record in recordGroup)
{
//filling stuff here
}
}
}
You need to project your group key to a string like this:
var groupedRecords = transformedRecords.GroupBy(x => String.Format("{0}-{1}-{2}-{3}",
x.Name,
x.DateTo.Value.Year,
x.DateTo.Value.Month,
x.DateTo.Value.Day));
Then you can iterate over the groups and check for existence of a certain key in your dictionary:
foreach(var group in groupedRecords)
{
if(!chartInformation.ContainsKey(group.Key))
{
chartInformation.Add(group.Key, 0)
}
}
However, keep in mind that projecting your key to a string as shown above can lead to collisions, i.e. rows that belong to different groups may end up in the same group.
Hope this helps.