Lambda expression, from Python to C# - c#

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).

Related

Remove duplicates in a list of XYZ points

Mylist.GroupBy(x => new{x.X, x.Y}).Select(g => g.First()).ToList<XYZ>();
The above code works fine for me. I only want to compare the points based on the round(5) of the point component.
For example x.X = 16.838974347323224 should be only compared as x.X = 16.83897 because I experienced some inaccuracy after the round 5. Any suggestions?
Solution:
Mylist.GroupBy(x => new { X = Math.Round(x.X,5), Y = Math.Round(x.Y,5) })
.Select(g => g.First()).ToList();
Using Round can create a situation where two numbers, even though incredibly close to each other, can end up being considered distinct.
Take this example:
var Mylist = new []
{
new { X = 1.0000051, Y = 1.0 },
new { X = 1.0000049, Y = 1.0 },
new { X = 1.1, Y = 1.0 },
new { X = 1.0, Y = 1.005 },
};
The first two values are very close - in fact they differ in the 6th decimal place.
By what if we run this code:
var result =
Mylist
.GroupBy(x => new
{
X = Math.Round(x.X,5, MidpointRounding.AwayFromZero),
Y = Math.Round(x.Y,5, MidpointRounding.AwayFromZero)
})
.Select(g => g.First())
.ToList();
The result is:
The rounding has allowed these two values to be kept.
The correct approach is to filter by distance. If a subsequent value is within a threshold of the previous values it should be discarded.
Here's the code that does that:
var threshold = 0.000001;
Func<double, double, double, double, double> distance
= (x0, y0, x1, y1) =>
Math.Sqrt(Math.Pow(x1 - x0, 2.0) + Math.Pow(y1 - y0, 2.0));
var result = Mylist.Skip(1).Aggregate(Mylist.Take(1).ToList(), (xys, xy) =>
{
if (xys.All(xy2 => distance(xy.X, xy.Y, xy2.X, xy2.Y) >= threshold))
{
xys.Add(xy);
}
return xys;
});
Now if we run that on the Mylist data we get this:
This is a better ideal for removing duplicates.
To do so use Math.Round:
var result = Mylist.GroupBy(x => new { X = Math.Round(x.X,5, MidpointRounding.AwayFromZero), Y = Math.Round(x.Y,5, MidpointRounding.AwayFromZero) })
.Select(g => g.First()).ToList();
However if what you want is to remove duplicates then instead of GroupBy go for one of these:
Select rounded and then Distinct:
var result = Mylist.Select(item => new XYZ { X = Math.Round(item.X,5, MidpointRounding.AwayFromZero),
Y = Math.Round(item.Y,5, MidpointRounding.AwayFromZero)})
.Distinct().ToList();
Distinct and override Equals and GetHashCode - (equals will do the rounding) - wouldn't suggest
Distinct and implement a custom IEqualityComparer:
public class RoundedXyzComparer : IEqualityComparer<XYZ>
{
public int RoundingDigits { get; set; }
public RoundedXyzComparer(int roundingDigits)
{
RoundingDigits = roundingDigits;
}
public bool Equals(XYZ x, XYZ y)
{
return Math.Round(x.X, RoundingDigits, MidpointRounding.AwayFromZero) == Math.Round(y.X, RoundingDigits, MidpointRounding.AwayFromZero) &&
Math.Round(x.Y,RoundingDigits, MidpointRounding.AwayFromZero) == Math.Round(y.Y, RoundingDigits, MidpointRounding.AwayFromZero);
}
public int GetHashCode(XYZ obj)
{
return Math.Round(obj.X, RoundingDigits, MidpointRounding.AwayFromZero).GetHashCode() ^
Math.Round(obj.Y, RoundingDigits, MidpointRounding.AwayFromZero).GetHashCode();
}
}
//Use:
myList.Distinct(new RoundedXyzComparer(5));

How so I take the Top N (percentage) values in a dictionary?

I have a dictionary with a string key and integer value. The value represents the number of occurrences of the key.
How do I create a new dictionary with the keys and values representing the top 25% of values? The sum of the values should be equal to or greater than the sum of all values. For example, if my dictionary contains 5 items with values (5, 3, 2, 1, 1) and I want the top 50%, the new dictionary would contain values (5, 3) because their sum is 8 and that is >= 50% of 12. This dictionary needs to be sorted descending by value and then the top N taken such that their sum meets the specified percentage.
This code gives me the top N but is based on a known count. How do I take into account the desired percentage?
var topItemsCount = dictionary.OrderByDescending(entry => entry.Value)
.Take(topN)
.ToDictionary(pair => pair.Key, pair => pair.Value);
Something like:
var topItemsCount = dictionary.OrderByDescending(entry => entry.Value)
.Take(Math.Floor(dictionary.Count * 0.25))
.ToDictionary(pair => pair.Key, pair => pair.Value);
Running .Count on a dictionary returns the number of key-value pairs in the collection. Taking Math.Floor rounds it down to the nearest int.
Edited to reflect comments
I would probably just use a simple non-linq solution to achieve what you want. Maybe more verbose, but it's pretty clear to anyone what it does:
var total = dictionary.Sum(e => e.Value);
var cutoff = total * 0.5;
var sum = 0;
var pairs = new List<KeyValuePair<string, int>>();
foreach (var pair in dictionary.OrderByDescending(e => e.Value))
{
sum += pair.Value;
pairs.Add(pair);
if (sum > cutoff)
break;
}
dictionary = pairs.ToDictionary(pair => pair.Key, pair => pair.Value);
One more edit
If you really want more linq, you could try holding an accumulated class level variable.
private static int sum = 0;
static void Main(string[] args)
{
var dictionary = new Dictionary<string, int>()
{
{"1",5},
{"2",3},
{"3",2},
{"4",1},
{"5",1},
};
var total = dictionary.Sum(e => e.Value);
var cutoff = total * 0.5;
var filtered = dictionary.OrderByDescending(e => e.Value)
.TakeWhile(e => Add(e.Value).Item1 < cutoff)
.ToDictionary(pair => pair.Key, pair => pair.Value);
}
private static Tuple<int, int> Add(int x)
{
return Tuple.Create(sum, sum += x);
}
It's a bit convoluted with the add function returning a tuple because you are including the first value that breaches the cut off in the result (i.e. even if 5 + 3 = 8 is greater than the cut off 6, you still include 3).
Rephrasing the question, into two parts:
Given a list of strings and values, find a value representing the Nth percentage
Given a list of string and values, and a value representing the Nth percentage, return a new list of string and values having values greater than or equal to the given number.
Question 1 would look like
double percent = inputValue;
double n = dictionary.Values.Sum() * percent;
Question 2 would look like:
Dictionary<string, int> newValues = dictionary.OrderByDescending(_ => _.Value)
.Aggregate(
new {sum = 0.0, values = new Dictionary<string, int>()},
(sumValues, kv) =>
{
if (sumValues.sum <= n)
sumValues.values.Add(kv.Key, kv.Value);
return new {sum = sumValues.sum + kv.Value, values = sumValues.values};
},
sumValues => sumValues.values);
You could also use a for loop and a running sum, but for running totals with limited scope, I like the compactness of the Aggregate function. The downside to this is that the entire source Dictionary is still iterated. A custom iterator method would get around this. For example:
public static class Extensions
{
public static IEnumerable<TThis> TakeGreaterThan<TThis>(this IEnumerable<TThis> source, Func<TThis, double> valueFunc, double compareTo)
{
double sum = 0.0;
IEnumerable<TThis> orderedSource = source.OrderByDescending(valueFunc);
var enumerator = orderedSource.GetEnumerator();
while (sum <= compareTo && enumerator.MoveNext())
{
yield return enumerator.Current;
sum += valueFunc(enumerator.Current);
}
}
}
Used as
Dictionary<string, int> newValues = dictionary.TakeGreaterThan(_ => _.Value, n).ToDictionary(_ => _.Key, _ => _.Value);
May be this?
var dictionary = new Dictionary<string, int>()
{
{"1",5},
{"2",3},
{"3",2},
{"4",1},
{"5",1},
};
var max = dictionary.Values.Max();
int percent = 50;
int percentageValue = max*percent /100;
var topItems = dictionary.OrderByDescending(entry => entry.Value)
.TakeWhile(x => x.Value > percentageValue)
.ToDictionary(pair => pair.Key, pair => pair.Value);
foreach (var item in topItems)
{
Console.WriteLine(item.Value);
}
Outputs:
5
3

Join two dictionaries by value diffs

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.

zipping/merging two sorted lists

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...

Merging sequences by type With LINQ

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

Categories