I have these two dictionaries:
Dictionary<char, double> analyzed_symbols = new Dictionary<char, double>();
Dictionary<char, double> decode_symbols = new Dictionary<char, double>();
I need to create another dictionary that should have their keys as key and value, like this:
Dictionary<char, char> replace_symbols = new Dictionary<char, char>();
The condition to "join" them is that difference between values should be minimal, like this:
Math.Min(Math.Abs(analyzed_symbols[key] - decode_symbols[key]))
I guess I should use LINQ for this purpose but can't figure out how to write query properly.
Data Sample:
analyzed_symbols = [a, 173], [b, 1522], [z, 99]
decode_symbols = [в, 100], [д, 185], [e, 1622]
For these dicts output data should look like this:
replace_symbols = [z, в], [b, е], [a, д]
I've found question that is pretty close to what I need, but not exactly. Snowy asks there about one close value, but I need to do the same thing for two dictionaries.
This is my take on it:
var analyzed_symbols = new Dictionary<char, double>(){ {'a', 173}, {'b', 1522}, {'z', 99} };
var decode_symbols = new Dictionary<char, double>(){ {'в', 100}, {'д', 185}, {'e', 1622} };
var q = from a in analyzed_symbols
from d in decode_symbols
let tmp = new { A = a.Key, D = d.Key, Value = Math.Abs(a.Value - d.Value) }
group tmp by tmp.A into g
select new
{
Key = g.Key,
Value = g.OrderBy (x => x.Value).Select (x => x.D).First()
};
var replace_symbols = q.ToDictionary (x => x.Key, x => x.Value);
Okay, I'll try. I divided into several queries, because it's more readable that way.
//sorting values of the dictionaries to easily get closest
var analyzedSortedValues = analyzed_symbols.Values.OrderBy(k => k);
var decodeSortedValues = decode_symbols.Values.OrderBy(k => k);
//creating pairs of the closest values. Here I use iterator index i to skip
//some values that have been used already (is it correct?)
var t = analyzedSortedValues.Select((k, i) => new { a = k, d = decodeSortedValues.Skip(i).Any() ? decodeSortedValues.Skip(i).First() : -1 });
//printing results by getting appropriate keys from corresponding dictionaries
foreach (var item in t)
{
Console.WriteLine("[{0}, {1}]", analyzed_symbols.FirstOrDefault(kvp => kvp.Value == item.a).Key, decode_symbols.FirstOrDefault(kvp => kvp.Value == item.d).Key);
}
I am not exactly sure how to do it via LINQ but here is the longhand version of what you want to do.
private static Dictionary<char, char> BuildReplacementDictionary(Dictionary<char, double> analyzedSymbols,
Dictionary<char, double> decodeSymbols)
{
Dictionary<char, char> replaceSymbols = new Dictionary<char, char>(analyzedSymbols.Count);
foreach (KeyValuePair<char, double> analyzedKvp in analyzedSymbols)
{
double bestMatchValue = double.MaxValue;
foreach (KeyValuePair<char, double> decodeKvp in decodeSymbols)
{
var testValue = Math.Abs(analyzedKvp.Value - decodeKvp.Value);
if (testValue <= bestMatchValue)
{
bestMatchValue = testValue;
replaceSymbols[analyzedKvp.Key] = decodeKvp.Key;
}
}
}
return replaceSymbols;
}
What it does is it goes through each element of the analyzed dictionary, test every element of the decoded dictionary, and if that match is the same or better than the previous match it found it will use the new value from the decoded dictionary.
Related
I am trying to rewrite some thing from python to c#, I have managed to recreate the dictionaries I but I am having trouble understanding the dictionary comprehension in c#.
here is the python code I would like to recreate in c#
distances={1:.02,30:.001,1000:.001}
minSearch=(min(distances.items(), key=lambda x:x[1]))
this is the dictionary I have in c#
Dictionary<int, double> distDict = new Dictionary<int, double>();
Thanks for the answer here it is implemented
List<MapPoint> list = new List<MapPoint>();
list.Add(pointDict[Convert.ToInt32(startOid)]);
while (pointDict.Count()>1)
{
var shape = pointDict[Convert.ToInt32(startOid)];
pointDict.Remove(Convert.ToInt32(startOid));
var X = shape.X;
var Y = shape.Y;
var Z = shape.Z;
foreach(KeyValuePair<int,MapPoint> point in pointDict)
{
var X2 = point.Value.X;
var Y2 = point.Value.Y;
var Z2 = point.Value.Z;
var squaredZDist = Math.Pow((Z - Z2), 2);
var squaredDist = Math.Pow(Math.Sqrt(Math.Pow(X - X2, 2) + Math.Pow(Y - Y2, 2)),2);
var threeDSquaredDist = Math.Sqrt(squaredDist + squaredZDist);
distDict[point.Key] = threeDSquaredDist;
}
var minValue = distDict.Min(x => x.Value);
var minPair = distDict
.Where(x => x.Value == minValue)
.First();
startOid = minPair.Key;
list.Add(pointDict[minPair.Key]);
distDict.Clear();
}
Polyline polyline = PolylineBuilder.CreatePolyline(list);
var pipeLayer = mapView.Map.Layers.OfType<FeatureLayer>()
.Where(x=>x.Name == "PIPELINE")
.First();
MessageBox.Show(pipeLayer.Name.ToString());
var createFeatures = new EditOperation();
createFeatures.Name = "Create Polyline";
createFeatures.Create(pipeLayer, polyline);
createFeatures.Execute();
you can duplicate that python using:
var distDict = new Dictionary<int, double> {
{1,.02},{30,.001},{1000,.001}
};
var minValue = distDict.Min(x => x.Value);
var minPair = distDict
.Where(x => x.Value == minValue)
.First();
var expected = new KeyValuePair<int, double>(30, .001);
Assert.Equal(expected, minPair);
We can do this with:
KeyValuePair<int, double> minSearch = distDict.OrderBy(x => x.Value).First()
This is thus a KeyValuePair<int, double> that contains a Key and Value property of the dictionary entry with the smallest Value in the `Dictionary.
C# will not order the collection immediately with .OrderBy(..), but construct an OrderedEnumerable [GitHub]. This will normally result in the fact that the .First() will aim to calculate the smallest item in linear time, so O(n), and like #flakes says, constant memory complexity O(1).
i have two sorted dictionaries both with the type signature
i.e.
SortedDictionary<decimal, long> A
SortedDictionary<decimal, long> B
I want to merge the two lists where the key is the same, thus creating a new list like
SortedDictionary<decimal, KeyValuePair<long,long>>
or
SortedDictionary<decimal, List<long>>
This may not be the best way of approacing the situation but could someone give me a heads up on how to do this or a better way to approach it.
This is what I've got:
SortedDictionary<decimal, List<long>> merged = new SortedDictionary<decimal, List<long>>
(
A.Union(B)
.ToLookup(x => x.Key, x => x.Value)
.ToDictionary(x => x.Key, x => new List<long>(x))
);
EDIT: Above solution selects keys not included in both collections. This should select where keys are same:
SortedDictionary<decimal, List<long>> merged = new SortedDictionary<decimal, List<long>>
(
A.Where(x=>B.ContainsKey(x.Key))
.ToDictionary(x => x.Key, x => new List<long>(){x.Value, B[x.Key]})
);
You can do this simply using LINQ:
var query = from a in A
join b in B
on a.Key equals b.Key
select new {
Key = a.Key,
Value = Tuple.Create(a.Value, b.Value)
};
var merged = new SortedDictionary<decimal, Tuple<long, long>>(
query.ToDictionary(x => x.Key, x => x.Value)
);
I think you should use Tuple<long, long> as your TValue in the merged dictionary.
Another LINQ way of doing this that I think captures the intent better in terms of set operations:
SortedDictionary<decimal, long> a = new SortedDictionary<decimal, long>();
SortedDictionary<decimal, long> b = new SortedDictionary<decimal, long>();
a.Add(0, 10);
a.Add(1, 10);
a.Add(2, 100);
a.Add(100, 1);
b.Add(0, 4);
b.Add(4, 4);
b.Add(2, 10);
var result = a.Union(b)
.GroupBy(x => x.Key)
.ToDictionary(x => x.Key, x => x.Select(y => (long)y.Value).ToList());
Try something like this, it not easy:
Dictionary<decimal, long> dic1 = new Dictionary<decimal, long>{ {3,23}, {2,3}, {5,4}, {6,8}};
Dictionary<decimal, long> dic2 = new Dictionary<decimal, long>{ {3,2}, {2,5}, {5,14}, {12,2}};
//recover shared keys (the keys that are present in both dictionaries)
var sharedKeys = dic1.Select(dic => dic.Key).Intersect(dic2.Select(d2=>d2.Key));
sharedKeys.Dump();
//add to the fìnal dictionary
var final = new Dictionary<decimal, List<long>>();
foreach(var shk in sharedKeys) {
if(!final.ContainsKey(shk))
final[shk] = new List<long>();
final[shk].Add(dic1[shk]);
final[shk].Add(dic2[shk]);
}
**EDIT**
//Skip below part if you need only keys present on both dictionaries.
///-----------------------------------------------------------------
//get unique keys present in Dic1 and add
var nonsharedkeys1 = dic1.Select(d=>d.Key).Where(k=>!sharedKeys.Contains(k));
foreach(var nshk in nonsharedkeys1) {
final[nshk] = new List<long>();
final[nshk].Add(dic1[nshk]);
}
//get unique keys present in Dic2 and add
var nonsharedkeys2 = dic2.Select(d=>d.Key).Where(k=>!sharedKeys.Contains(k));
foreach(var nshk in nonsharedkeys2) {
final[nshk] = new List<long>();
final[nshk].Add(dic2[nshk]);
}
Should work for you.
You could "abuse" Concat and Aggregate like this:
var A = new SortedDictionary<decimal,long>();
var B = new SortedDictionary<decimal,long>();
A.Add(1, 11);
A.Add(2, 22);
A.Add(3, 33);
B.Add(2, 222);
B.Add(3, 333);
B.Add(4, 444);
var C = A.Concat(B).Aggregate(
new SortedDictionary<decimal, List<long>>(),
(result, pair) => {
List<long> val;
if (result.TryGetValue(pair.Key, out val))
val.Add(pair.Value);
else
result.Add(pair.Key, new[] { pair.Value }.ToList());
return result;
}
);
foreach (var x in C)
Console.WriteLine(
string.Format(
"{0}:\t{1}",
x.Key,
string.Join(", ", x.Value)
)
);
The resulting output:
1: 11
2: 22, 222
3: 33, 333
4: 444
This is pretty much the same as if you wrote a "normal" foreach and would in fact work on any IEnumerable<KeyValuePair<decimal, long>> (not just SortedDictionary<decimal, long>) and is easy to extend to more than two input collections if needed.
Unfortunately, it also completely disregards the fact that the input SortedDictionary is, well, sorted, so performance is not optimal. For optimal performance you'd have to fiddle with linearly advancing separate IEnumerator for each of the input sorted dictionaries, while constantly comparing the underlying elements - you could completely avoid TryGetValue that way...
I am trying to create a dictionary from 2 lists where one list contains keys and one list contains values. I can do it using for loop but I am trying to find if there is a way of doing it using LINQ.
Sample code will be helpfull. Thanks!!!!
In .NET4 you could use the built-in Zip method to merge the two sequences, followed by a ToDictionary call:
var keys = new List<int> { 1, 2, 3 };
var values = new List<string> { "one", "two", "three" };
var dictionary = keys.Zip(values, (k, v) => new { Key = k, Value = v })
.ToDictionary(x => x.Key, x => x.Value);
List<string> keys = new List<string>();
List<string> values = new List<string>();
Dictionary<string, string> dict = keys.ToDictionary(x => x, x => values[keys.IndexOf(x)]);
This of course assumes that the length of each list is the same and that the keys are unique.
UPDATE: This answer is far more efficient and should be used for lists of non-trivial size.
You can include the index in a Select expression to make this efficient:
var a = new List<string>() { "A", "B", "C" };
var b = new List<string>() { "1", "2", "3" };
var c = a.Select((x, i) => new {key = x, value = b[i]}).ToDictionary(e => e.key, e => e.value );
foreach (var d in c)
Console.WriteLine(d.Key + " = " + d.Value);
Console.ReadKey();
var dic = keys.Zip(values, (k, v) => new { k, v })
.ToDictionary(x => x.k, x => x.v);
You can use this code and working perfectly.
C# Code:
var keys = new List<string> { "Kalu", "Kishan", "Gourav" };
var values = new List<string> { "Singh", "Paneri", "Jain" };
Dictionary<string, string> dictionary = new Dictionary<string, string>();
for (int i = 0; i < keys.Count; i++)
{
dictionary.Add(keys[i].ToString(), values[i].ToString());
}
foreach (var data in dictionary)
{
Console.WriteLine("{0} {1}", data.Key, data.Value);
}
Console.ReadLine();
Output Screen:
I want to use LINQ to convert this
IEnumerable<int>[] value1ByType = new IEnumerable<int>[3];
value1ByType[0]= new [] { 0};
value1ByType[1]= new [] {10,11};
value1ByType[2]= new [] {20};
var value2ToType = new Dictionary<int,int> {
{100,0},
{101,1},
{102,2},
{103,1}};
to this
var value2ToValue1 = new Dictionary<int,int> {
{100, 0},
{101,10},
{102,20},
{103,11}};
Is there a way to do this with LINQ? Without LINQ I would use multiple IEnumerators, one for each IEnumerable of value1ByType. like this:
// create enumerators
var value1TypeEnumerators = new List<IEnumerator<int>>();
for (int i = 0; i < value1ByType.Length; i++)
{
value1TypeEnumerators.Add(value1ByType[i].GetEnumerator());
value1TypeEnumerators[i].MoveNext();
}
// create wanted dictionary
var value2ToValue1 = new Dictionary<int, int>();
foreach (var item in Value2ToType)
{
int value1=value1TypeEnumerators[item.Value].Current;
value2ToValue1.Add(item.Key, value1);
value1TypeEnumerators[item.Value].MoveNext();
}
Any Idea how to do this in LINQ?
Not pure but you can at least do ...
var enumerators = value1ByType.Select(v => v.GetEnumerator()).ToArray();
var value2ToValue1 = value2ToType
.ToDictionary(x => x.Key, x => { enumerators[x.Value].MoveNext(); return enumerators[x.Value].Current; });
But there are so many ways this could go wrong it begs the question - why was the data in those data-structures anyway? and can you fix that instead? How did you end up with exactly the right number of references in the 2nd data structure to elements in the first?
I'm pretty sure that #Hightechrider's solution is most performant than this one, but if you really like the syntax sugar way, you can do it like this:
public IDictionary<int, int> MergeSequences(IEnumerable<int>[] value1ByType, Dictionary<int, int> value2ToType)
{
int pos = 0;
var value1ByTypePos = from byType in value1ByType
select new { Pos = pos++, Enumerator = byType.GetEnumerator() };
return (from byType in value1ByTypePos
join toType in value2ToType
on byType.Pos equals toType.Value
select new { toType.Key, Value = byType.Enumerator.GetNext() })
.ToDictionary(pair => pair.Key, pair => pair.Value);
}
I've added an extension method to the IEnumerator interface like this:
public static T GetNext<T>(this IEnumerator<T> enumerator)
{
if (!enumerator.MoveNext())
throw new InvalidOperationException();
return enumerator.Current;
}
Now you have to be aware that any of this solutions can give you slightly different results, depending on how elements in the dictionary are enumerated. For example, another valid result to this code is:
var value2ToValue1 = new Dictionary<int,int> {
{100, 0},
{103, 10},
{102, 20},
{101, 11}};
Notice that now 101 is paired with 11 and 103 is paired with 10. If this is a problem, then you should use a SortedDictionary<int, int> when defining value2ToType variable.
What you can do for sure is replace the first part with the following:
var value1TypeEnumerators = value1ByType.ToList();
instead of using an enumerator.
If I do not care about performance I could also write:
var value2Ordered = Value2ToType.OrderBy(x => x.Value).Select(x=>x.Key);
var value1Ordered = from item in value1ByType from subitem in item select subitem;
var value2ToValue1 = value2Ordered.Zip(value1Ordered, (x, y) => new { Key = x, Value = y })
.ToDictionary(item => item.Key, item => item.Value);
I used the zip method from a stackoverflow community wiki. I didn't test this with the c#4.0 zip method
How can I change the value of a number of keys in a dictionary.
I have the following dictionary :
SortedDictionary<int,SortedDictionary<string,List<string>>>
I want to loop through this sorted dictionary and change the key to key+1 if the key value is greater than a certain amount.
As Jason said, you can't change the key of an existing dictionary entry. You'll have to remove/add using a new key like so:
// we need to cache the keys to update since we can't
// modify the collection during enumeration
var keysToUpdate = new List<int>();
foreach (var entry in dict)
{
if (entry.Key < MinKeyValue)
{
keysToUpdate.Add(entry.Key);
}
}
foreach (int keyToUpdate in keysToUpdate)
{
SortedDictionary<string, List<string>> value = dict[keyToUpdate];
int newKey = keyToUpdate + 1;
// increment the key until arriving at one that doesn't already exist
while (dict.ContainsKey(newKey))
{
newKey++;
}
dict.Remove(keyToUpdate);
dict.Add(newKey, value);
}
You need to remove the items and re-add them with their new key. Per MSDN:
Keys must be immutable as long as they are used as keys in the SortedDictionary(TKey, TValue).
You can use LINQ statment for it
var maxValue = 10
sd= sd.ToDictionary(d => d.key > maxValue ? d.key : d.Key +1, d=> d.Value);
If you don't mind recreating the dictionary, you could use a LINQ statment.
var dictionary = new SortedDictionary<int, SortedDictionary<string, List<string>>>();
var insertAt = 10;
var newValues = dictionary.ToDictionary(
x => x.Key < insertAt ? x.Key : x.Key + 1,
x => x.Value);
return new SortedDictionary<int, SortedDictionary<string, List<string>>>(newValues);
or
var dictionary = new SortedDictionary<int, SortedDictionary<string, List<string>>>();
var insertAt = 10;
var newValues = dictionary.ToDictionary(
x => x.Key < insertAt ? x.Key : x.Key + 1,
x => x.Value);
dictionary.Clear();
foreach(var item in newValues) dictionary.Add(item.Key, item.Value);