I have two lists of dictionary on which I am doing set operations. I will illustrate what I am doing and what I am trying to achieve as an example:
var A = new List<Dictionary<string, int>>();
var B = new List<Dictionary<string, int>>();
A.Add(new Dictionary <string, int> { {"KeyA",1}, {"KeyB", 2} });
A.Add(new Dictionary <string, int> { {"KeyA",3}, {"KeyB", 5} });
B.Add(new Dictionary <string, int> { {"KeyA",6}, {"KeyB", 8}, {"KeyC", 11} });
B.Add(new Dictionary <string, int> { {"KeyA",3}, {"KeyB", 7}, {"KeyC", 15} });
var result = A.Intersect(B, new KeyComparer("KeyA"));
This gives me back the list of A using KeyA for intersection and I get a single row with {"KeyA",3}, {"KeyB", 5} as the result. What if I want to add {KeyC, 15} from B to the result when intersection has happened.
I hope I am clear with the question.
If I've correctly understood your question, you want to add some other item to the sequence once you've done the intersection... and then, what you need is Enumerable.Concat:
var result = A.Intersect(B, new KeyComparer("KeyA"))
.Concat(B.Last().Where(pair => pair.Key == "KeyC"));
Related
I have the below code in which i branch for each sample in a dictionary , is there a way either by using LINQ or any other method in which i can avoid branching -> may be a functional approach
Dictionary<string, int> samples = new Dictionary<string, int>()
{
{"a", 1},
{"aa", 2},
{"b", 1},
{"bb", 3}
};
foreach (var sample in samples)
{
if (sample.Value ==)
{
Console.WriteLine("sample passed");
}
else if (sample.Value == 2)
{
Console.WriteLine("sample isolated");
}
else if (sample.Value == 3)
{
Console.WriteLine("sample biased");
}
}
UPD
What if i have other type of comprasion:
foreach (var sample in samples)
{
if (sample.Value <= 1)
{
Console.WriteLine("sample passed");
}
else if (sample.Value <= 2)
{
Console.WriteLine("sample isolated");
}
else if (sample.Value <= 3)
{
Console.WriteLine("sample biased");
}
}
One option would be to create a list of Actions that you wish to perform, then execute them based on the index. This way your methods can be quite varied. If you need to perform very similar actions for each option, then storing a list of values would be a better than storing Actions.
List<Action> functions = new List<Action>();
functions.Add(() => Console.WriteLine("sample passed"));
functions.Add(() => Console.WriteLine("sample isolated"));
functions.Add(() => Console.WriteLine("sample biased"));
foreach (var sample in samples)
{
Action actionToExecute = functions[sample.Value - 1];
actionToExectute();
}
If you wanted to use a dictionary as your comment implies:
Dictionary<int, Action> functions = new Dictionary<int, Action>();
functions.Add(1, () => Console.WriteLine("sample passed"));
functions.Add(2, () => Console.WriteLine("sample isolated"));
functions.Add(3, () => Console.WriteLine("sample biased"));
foreach (var sample in samples)
{
Action actionToExecute = functions[sample.Value];
actionToExectute();
}
For this concrete case you can introduce another map(Dictionary or an array, as I did):
Dictionary<string, int> samples = new Dictionary<string, int>()
{
{"a", 1},
{"aa", 2},
{"b", 1},
{"bb", 3}
};
var map = new []
{
"sample passed",
"sample isolated",
"sample biased"
};
foreach (var sample in samples)
{
Console.WriteLine(map[sample.Value - 1]);
}
As for actual code it highly depends on usecases and how you want to handle faulty situations.
UPD
It seems that if you will be using dictionary for your map there still will be some branching, but if you will not have misses branch prediction should take care of it.
So you have a Dictionary<string, int>. Every item in the dictionary is a KeyValuePair<string, int>. I assume that the string is the name of the sample (identifier), and the int is a number that says something about the sample:
if the number equals 0 or 1, the sample is qualified as Passed;
if the number equals 2, then you call it Isolated
if the number equals 3, then you call it Biased.
All higher numbers are not interesting for you.
You want to group the samples in Passed / Isolated / Biased samples.
Whenever you have a sequence of similar items and you want to make groups of items, where every element has something in common with the other elements in the group, consider using one of the overloads of Enumerable.GroupBy
Let's first define an enum to hold your qualifications, and a method that converts the integer value of the sample into the enum:
enum SampleQualification
{
Passed,
Isolated,
Biased,
}
SampleQualification FromNumber(int number)
{
switch (number)
{
case 2:
return SampleQualification.Isolated;
case 3:
return SampleQualification.Biased;
default:
return SampleQualification.Passed;
}
}
Ok, so you have your dictionary of samples, where every key is a name of the sample and the value is a number that can be converted to a SampleQualification.
Dictionary<string, int> samples = ...
var qualifiedSamples = samples // implements IEnumerable<KeyValuePair<string, int>>
// keep only samples with Value 0..3
.Where(sample => 0 <= sample.Value && sample.Value <= 3)
// Decide where the sample is Passed / Isolated / Biased
.Select(sample => new
{
Qualification = FromNumber(sample.Value)
Name = sample.Key, // the name of the sample
Number = sample.Value,
})
// Make groups of Samples with same Qualification:
.GroupBy(
// KeySelector: make groups with same qualification:
sample => sample.Qualification,
// ResultSelector: take the qualification, and all samples with this qualification
// to make one new:
(qualification, samplesWithThisQualification) => new
{
Qualification = qualification,
Samples = samplesWithThisQualification.Select(sample => new
{
Name = sample.Name,
Number = sample.Number,
})
.ToList(),
});
The result is a sequence of items. Where every item has a property Qualification, which holds Passed / Isolated / Biased. Every item also has a list of samples that have this qualification.
// Process Result
foreach (var qualifiedSample in qualifiedSamples)
{
Console.WriteLine("All samples with qualification " + qualifiedSample.Qualification);
foreach (var sample in qualifiedSample.Samples)
{
Console.WriteLine({0} - {1}, sample.Name, sample.Value);
}
}
I have a Dictionary<string, decimal?>, and i would like to be able to sum the decimals by distinct string. So say i have the below inputs in dictionary,
"1", 20.00
"1", 35.00
"2", 10.00
"3", 15.00
"3", 30.00
I would like the following output to a new Dictionary
"1", 55.00
"2", 10.00
"3", 45.00
I'm guessing it would be something like
foreach(var item in dictionary)
{
newDictionary.Add(not sure what would go here, maybe some sort of linq query for distinct and sum?);
}
Assuming the same List of key value pairs as in the other answers:
var myList = New List<KeyValuePair<string, decimal?>> {
new KeyValuePair<string, decimal?>("1", (decimal)10.00),
new KeyValuePair<string, decimal?>("1", (decimal)15.00),
new KeyValuePair<string, decimal?>("2", (decimal)20.00),
new KeyValuePair<string, decimal?>("3", (decimal)30.50),
new KeyValuePair<string, decimal?>("3", (decimal)17.500)
};
var myResults = myList.GroupBy(p => p.Key)
.ToDictionary(g => g.Key, g=>g.Sum(p=>p.Value))
The keys in a dictionary can't be repeated, so the 2 first entries won't fit in a dictionary.
I think you may have a list of objects that you can loop, then you can use a dictionary to store the total for each "key"
something like
Dictionary<string, double> totals = new Dictionary<string, double>();
List<Tuple<string, double>> entries = new List<Tuple<string, double>>() {
new Tuple<string, double>("1",20.00),
new Tuple<string, double>("1",35.00),
new Tuple<string, double>("2",10.00),
new Tuple<string, double>("3",15.00),
new Tuple<string, double>("3",30.00)
};
foreach (var e in entries)
{
if (!totals.Keys.Contains(e.Item1))
{
totals[e.Item1] = 0;
}
totals[e.Item1] += e.Item2;
}
You can not have Dictionary object with duplicate keys. You would see ArgumentException when you try to add an existing key into the Dictionary object.
Refer: https://msdn.microsoft.com/en-us/library/xfhwa508(v=vs.110).aspx
As mentioned here You can't use Dictionary if you are using same keys, because they must be Unique.
You can use list of KeyPair though, which is closest to Dictionary, then you're code will look like this:
List<KeyValuePair<string, decimal?>> myList = new List<KeyValuePair<string, decimal?>>();
myList.Add(new KeyValuePair<string, decimal?>("1", (decimal)10.00));
myList.Add(new KeyValuePair<string, decimal?>("1", (decimal)15.00));
myList.Add(new KeyValuePair<string, decimal?>("3", (decimal)30.50));
myList.Add(new KeyValuePair<string, decimal?>("3", (decimal)17.500));
Dictionary<string, decimal?> sums = new Dictionary<string, decimal?>(); //This can be a dictionary because the keys will be unique after grouping
foreach (var item in myList.GroupBy(m => m.Key))
{
string currentKey = item.FirstOrDefault().Key;
sums.Add(currentKey, myList.Where(j => j.Key == currentKey).Sum(o => o.Value));
}
I have a var myDictionary = new Dictionary<int, string> with the following data:
123, "Do this"
234, "Do that"
345, "Do something"
123, "Do that"
567, "Do anything"
234, "Do something"
What's the best way for me to retrieve only the values for any given key? Say, I want to get only the values for 123.
If you want to have multiple different values grouped under one key you probably have to change the structure of your dictionary to something like this:
var myDictionary = new Dictionary<int, List<string>>();
You then initialize the list for each new key or if the key's already there you add the item to the list.
if (!myDictionary.ContainsKey(myKey))
{
myDictionary[myKey] = new List<string();
}
myDictionary[myKey].Add(myItem);
And you get the items in a standard way:
if (myDictionary.ContainsKey(myKey))
{
var results = myDictionary[myKey];
}
This will give you a list that you can then query to see what items have been returned.
A Dictionary object cannot have multiple items with the same key. Instead, you want to use KeyValuePair.
The code might look something like this:
var items = new List<KeyValuePair<int, String>>();
items.Add(new KeyValuePair<int, String>(123, "Do this"));
items.Add(new KeyValuePair<int, String>(234, "Do that"));
items.Add(new KeyValuePair<int, String>(345, "Do something"));
items.Add(new KeyValuePair<int, String>(123, "Do that"));
items.Add(new KeyValuePair<int, String>(567, "Do anything"));
items.Add(new KeyValuePair<int, String>(234, "Do something"));
// This is the key you are looking for
int desiredValue = 123;
foreach (var v in items.Where(kvp => kvp.Key == desiredValue))
{
// Access the values you need here
Console.WriteLine(v.Value);
}
Where the output would be:
Do this
Do that
You can see this example in action here. Happy coding :)
See code below
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.Xml.Linq;
namespace ConsoleApplication61
{
class Program
{
static void Main(string[] args)
{
Dictionary<int, List<string>> dict = new Dictionary<int, List<string>>() {
{123, new List<string>() {"Do this", "Do that"}},
{234, new List<string>() {"Do that", "Do something"}},
{345, new List<string>() {"Do something"}},
{567, new List<string>() {"Do anything"}}
};
List<string> results = dict[123];
}
}
}
I create the list like
var list = new List<KeyValuePair<string, string>>();
list.Add(new KeyValuePair<string, string>("1", "abc"));
list.Add(new KeyValuePair<string, string>("2", "def"));
list.Add(new KeyValuePair<string, string>("3", "ghi"));
How to select the value from this list.
Which means I need to pass 1 to the list and need to take the equal value "abc".How to do this? input is 1,output is abc.
It sounds like you just want:
var value = list.First(x => x.Key == input).Value;
That's if you're sure the key will be present. It's slightly trickier otherwise, partly because KeyValuePair is a struct. You'd probably want:
var pair = list.FirstOrDefault(x => x.Key == input);
if (pair.Key != null)
{
// Yes, we found it - use pair.Value
}
Any reason you're not just using a Dictionary<string, string> though? That's the more natural representation of a key/value pair collection:
var dictionary = new Dictionary<string, string>
{
{ "1", "abc" },
{ "2", "def" },
{ "3", "ghi" }
};
Then:
var value = dictionary[input];
Again, assuming you know the key will be present. Otherwise:
string value;
if (dictionary.TryGetValue(input, out value))
{
// Key was present, the value is now stored in the value variable
}
else
{
// Key was not present
}
Why are you not using a Dictionary? http://msdn.microsoft.com/en-us/library/xfhwa508.aspx
It seems to me this would solve your problem, and it's much easier to use.
Is there a better way to code the Where this:
IDictionary<string, string> p = new Dictionary<string, string>();
p.Add("Apple", "1");
p.Add("Orange", "2");
p.Add("Pear", "3");
p.Add("Grape", "4");
p.Add("Pineapple", "5");
//This is a unique list
var retVal = p.Where(k => k.Key.Contains("Apple") || k.Key.Contains("Pear") || k.Key.Contains("Grape"));
Some History Below
I have a dictionary of strings like the following:
IDictionary<string,string>
The contents look like this:
Apple,1
Orange,2
Pear,3
Grape,4
...many more
How do i return only a few items from my dictionary like so
if (true)
{
//return only 3 apple,pear&grape items out of the dozens in the list into a new variable
}
You can just take the first 3 items...
theDictionary.Take(3);
Or filter and take specific items...
string[] itemsIWant = { "Apple", "Pear", "Grape" };
theDictionary.Where(o => itemsIWant.Contains(o.Key));
Or sort randomly and take 3...
Random r = new Random();
theDictionary.OrderBy(o => r.Next()).Take(3);
check out
LINQ query to return a Dictionary<string, string>
That will really depend on the kind of filtering you want to achieve. But you can achieve it through Linq.
If you just want to get the first 3 items, you can do it like this:
theDictionary.Take(3);
If you want to get the first 3 items that begin with 'G', the you will do this:
theDictionary.Where(kv => kv.Key.StartsWith("G")).Take(3);
If you want to get the first 3 items that begin with 'G' regardless the casing, the you will do this:
theDictionary.Where(kv => kv.Key.ToLower().StartsWith("g")).Take(3);
Last, but not least, if you want to get 3 items randomly, you will do this:
Random rand = new Random();
theDictionary.OrderBy(kv => rand.Next()).Take(3);