As you can see, multiply is pretty easy for row major matrices.
But in my case i have column major matrix, how can i multiply column major matrices using linq?
Row major matrix
double[][] M1 = { {a1, b1}, {a2, b2}, {a3, b3} };
double[] M2 = { a, b };
double[] M3 = M1.Select(inner => inner.Zip(M2, (x, y) => x*y).Sum()).ToArray();
Column major matrix
double[][] M1 = {{a1,a2,a3},{b1,b2,b3}};
double[] M2 = { a, b };
double[] M3 = ?;
These are expected results. (Sorry too lazy for writing a sample).
A = a1*a + b1*b;
B = a2*a + b2*b;
C = a3*a + b3*b;
I missed groupby solution.
double[] M3 = M1.SelectMany(inner => inner.Select((x, i) => (x, i))
.GroupBy(t => t.i, t => t.x, (t, e) =>
e.Zip(M2, (x, y) => x * y).Sum()))
.ToArray();
Related
I want to make a ranking from a list and output it on original order.
This is my code so far:
var data = new[] { 7.806468478, 7.806468478, 7.806468478, 7.173501754, 7.173501754, 7.173501754, 3.40877696, 3.40877696, 3.40877696,
4.097010736, 4.097010736, 4.097010736, 4.036494085, 4.036494085, 4.036494085, 38.94333318, 38.94333318, 38.94333318, 14.43588131, 14.43588131, 14.43588131 };
var rankings = data.OrderByDescending(x => x)
.GroupBy(x => x)
.SelectMany((g, i) =>
g.Select(e => new { Col1 = e, Rank = i + 1 }))
.ToList();
However, the result will be order it from descending:
What I want is to display by its original order.
e.g.: Rank = 3, Rank = 3, Rank = 3, Rank = 4, Rank = 4, Rank = 4, etc...
Thank You.
Using what you have, one method would be to keep track of the original order and sort a second time (ugly and potentially slow):
var rankings = data.Select((x, i) => new {Item = x, Index = i})
.OrderByDescending(x => x.Item)
.GroupBy(x => x.Item)
.SelectMany((g, i) =>
g.Select(e => new {
Index = e.Index,
Item = new { Col1 = e.Item, Rank = i + 1 }
}))
.OrderBy(x => x.Index)
.Select(x => x.Item)
.ToList();
I would instead suggest creating a dictionary with your rankings and joining this back with your list:
var rankings = data.Distinct()
.OrderByDescending(x => x)
.Select((g, i) => new { Key = g, Rank = i + 1 })
.ToDictionary(x => x.Key, x => x.Rank);
var output = data.Select(x => new { Col1 = x, Rank = rankings[x] })
.ToList();
As #AntonínLejsek kindly pointed out, replacing the above GroupBy call with Distinct() is the way to go.
Note doubles are not a precise type and thus are really not a good candidate for values in a lookup table, nor would I recommend using GroupBy/Distinct with a floating-point value as a key. Be mindful of your precision and consider using an appropriate string conversion. In light of this, you may want to define an epsilon value and forgo LINQ's GroupBy entirely, opting instead to encapsulate each data point into a (non-anonymous) reference type, then loop through a sorted list and assign ranks. For example (disclaimer: untested):
class DataPoint
{
decimal Value { get; set; }
int Rank { get; set; }
}
var dataPointsPreservingOrder = data.Select(x => new DataPoint {Value = x}).ToList();
var sortedDescending = dataPointsPreservingOrder.OrderByDescending(x => x.Value).ToList();
var epsilon = 1E-15; //use a value that makes sense here
int rank = 0;
double? currentValue = null;
foreach(var x in sortedDescending)
{
if(currentValue == null || Math.Abs(x.Value - currentValue.Value) > epsilon)
{
currentValue = x.Value;
++rank;
}
x.Rank = rank;
}
From review of the data you will need to iterate twice over the result set.
The first iteration will be to capture the rankings as.
var sorted = data
.OrderByDescending(x => x)
.GroupBy(x => x)
.Select((g, i) => new { Col1 = g.First(), Rank = i + 1 })
.ToList();
Now we have a ranking of highest to lowest with the correct rank value. Next we iterate the data again to find where the value exists in the overall ranks as:
var rankings = (from i in data
let rank = sorted.First(x => x.Col1 == i)
select new
{
Col1 = i,
Rank = rank.Rank
}).ToList();
This results in a ranked list in the original order of the data.
A bit shorter:
var L = data.Distinct().ToList(); // because SortedSet<T> doesn't have BinarySearch :[
L.Sort();
var rankings = Array.ConvertAll(data,
x => new { Col1 = x, Rank = L.Count - L.BinarySearch(x) });
I want to be able to get the nearest x-tens-place number above and below any number using C#
For example, if I have a 4-digit number and I want all the closes number above and below ending and set of 2-digit number like 30, 50, 80, or 00 then
2126 => 2100 and 2130
2146 => 2130 and 2150
2183 => 2180 and 2200
I want to be able to do this below 1 too, like if my set of levels are 0.0030, 0.0050, 0.0080 and 0.0000 then if I had the following numbers
1.0026 => 1.0000 and 1.0030
1.0046 => 1.0030 and 1.0050
1.0083 => 1.0080 and 1.0100
The purpose of this is to calculate hi/lo ranges around a given asset price and a set of range values.
Because this isn't really anything to do with 10's rounding you have to specify the number of digits that you want to truncate with and then iterate over the "set point" values to find the two closest points to the given input.
This is what I came up with:
Func<double, double[], int, double> lower = (x, sps, d) =>
sps
.Select(sp => sp + Math.Truncate(Math.Pow(10.0, d) * x) / Math.Pow(10.0, d))
.Where(v => v <= x)
.Last();
Func<double, double[], int, double> upper = (x, sps, d) =>
sps
.Select(sp => sp + Math.Truncate(Math.Pow(10.0, d) * x) / Math.Pow(10.0, d))
.Where(v => v >= x)
.First();
My input data is:
var data = new []
{
new
{
setpoints = new double[] { 0, 30, 50, 80, 100 },
digits = -2,
values = new double[] { 2126, 2146, 2183 },
},
new
{
setpoints = new [] { 0.0, 0.003, 0.005, 0.008, 0.01 },
digits = 2,
values = new [] { 1.0026, 1.0046, 1.0083 },
},
};
The results were calculated as:
var results =
data
.SelectMany(
x => x.values,
(x, v) => new
{
value = v,
lower = lower(v, x.setpoints, x.digits),
upper = upper(v, x.setpoints, x.digits)
});
The results I got were as expected:
What is the best way to apply SelectMany to get a cross join of three or more sequences using only extension methods? Is there any other way to get a cross join?
Test Data
var a = Enumerable.Range(11, 2);
var b = Enumerable.Range(21, 2);
var c = Enumerable.Range(31, 2);
Expected Result
X Y Z
11 21 31
11 21 32
11 22 31
11 22 32
12 21 31
12 21 32
12 22 31
12 22 32
What I tried
Here's the code that works but I wonder if there's any alternative that'd be easier to read and understand:
var d = a
.SelectMany(rb => b
.SelectMany(rc => c, (y, z) => new { Y = y, Z = z}),
(x, yz) => new { X = x, Y = yz.Y, Z = yz.Z });
The equivalent query expression is good but not what I'm looking for:
var e = from x in a
from y in b
from z in c
select new { X = x, Y = y, Z = z };
You can simplify (even if not much) your SelectMany query in this way:
var res = a.SelectMany(X => b.SelectMany(Y => c.Select(Z => new { X, Y, Z })));
You could use a Join that projects keys that always match.
var e = a.Join(b, x => true, y => true, (x, y) => new { A = x, B = y })
.Join(c, x => true, y => true, (x, y) => new { x.A, x.B, C = y });
Admittedly, it's probably less efficient than your SelectMany version.
I am still not sure if it's ok to make a custom method. But here it is anyway:
public static IEnumerable<IEnumerable<T>> CrossJoin<T>(params IEnumerable<T>[] sequences)
{
IEnumerable<IEnumerable<T>> result = new[] { Enumerable.Empty<T>() };
foreach (var sequence in sequences)
{
result = result.SelectMany(i => sequence.Select(s => i.Concat(new[] { s })));
}
return result;
}
If you add such a method, then the code that matters will become very readable:
var d = CrossJoin(
Enumerable.Range(11, 2),
Enumerable.Range(21, 2),
Enumerable.Range(31, 2)
);
Result:
Console.WriteLine("X Y Z");
foreach( var item in d ) {
Console.WriteLine(String.Join( ",", item ));
}
/*
X Y Z
11,21,31
11,21,32
11,22,31
11,22,32
12,21,31
12,21,32
12,22,31
12,22,32
*/
This question already has answers here:
Closed 11 years ago.
Possible Duplicate:
Nested “from” LINQ query expressed with extension methods
I'm sure this has been asked before, but I honestly couldn't find anything.
I'm curious what the equivalent syntax would be for the following using only built-in Linq extension methods:
var z1 =
from x in xs
from y in ys
select new { x, y };
I can get the same results with this:
var z2 = xs.SelectMany(x => ys.Select(y => new { x, y }));
But it produces different IL code, and the code is a bit convoluted and hard to understand. Is there a cleaner way to do this with extension methods?
Here's my entire test method as written:
private void Test()
{
var xs = new[] { 1D, 2D, 3D };
var ys = new[] { 4D, 5D, 6D };
var z1 =
from x in xs
from y in ys
select new { x, y };
var z2 = xs.SelectMany(x => ys.Select(y => new { x, y }));
}
Here's the [Edit: C# interp of the] IL code (using ILSpy):
private void Test()
{
double[] xs = new double[]
{
1.0,
2.0,
3.0
};
double[] ys = new double[]
{
4.0,
5.0,
6.0
};
var z =
from x in xs
from y in ys
select new
{
x = x,
y = y
};
var z2 = xs.SelectMany((double x) =>
from y in ys
select new
{
x = x,
y = y
});
}
One way would be:
var z2 = xs.SelectMany(x => ys, (x, y) => new {x, y});
If you really want to use a single LINQ extension method, then another candidate would be Join, with the outerKeySelector and innerKeySelector functions defined such that they will always produce equal values.
var z3 = xs.Join(ys, x => true, y => true, (x, y) => new { x, y });
This will, however, probably give more convoluted IL code than the nested from solution. Incidentally, MSDN uses the nested from in its example for a cross join; look at the first code snippet in How to: Perform Custom Join Operations (C# Programming Guide).
I have a normal GroupBy operation on an enumerable:
e.GroupBy(i => i.Property)
But if i.Property is really a collection, how would I break apart the collection and use the list's elements as grouping keys?
For example let's say I have two objects (Z, Y) that each have a list:
Z: { List = { A, B, C }}
Y: { List = { B, C, D }}
Now running the GroupBySubelement(o => o.List) would not group by the list itself, but would iterate over the list and generate the following Groupings.
{A, {Z}}
{B, {Z, Y}}
{C, {Z, Y}}
{D, {Y}
Is this possible?
Thanks!
Here's some example code that achieves what you want:
//This is just temporary data. Has the similar structure to what you want.
var parts = new[]
{
new
{
Name = "X",
Property = new[] {'A', 'B', 'C'}
},
new
{
Name = "Y",
Property = new[] {'B', 'C', 'D'}
},
new
{
Name = "Z",
Property = new char[] { }
}
};
var groupedBySub = from part in parts
from sub in part.Property
group part by sub;
foreach(var group in groupedBySub)
{
Console.WriteLine("{0} - {1}", group.Key, string.Join(", ", group.Select(x => x.Name)));
}
Which outputs:
A - X
B - X, Y
C - X, Y
D - Y
You can also achieve this in the method chain fashion:
var groupedBySub = parts.SelectMany(part => part.Property, (part, sub) => new {part, sub}).GroupBy(t => t.sub, t => t.part);
If you want to capture it with the list being empty:
var groupedBySub = from part in parts
from sub in part.Property.DefaultIfEmpty()
group part by sub;
Which when substituted for the code above, gives output:
A - X
B - X, Y
C - X, Y
D - Y
- Z
This would do:
var combinations = e.SelectMany(i => i.List.Select(x => new { x, i }));
var groups = combinations.GroupBy(c => c.x, c => c.i);
Part of the problem here is that you don't have a good data structure:
var z = new List<T>(); // I'm using T here, so let's pretend this is in a generic method
var y = new List<T>();
// add a bunch of stuff
There isn't really any algorithm that can get you what you want, because the variables Z and Y are not really known to the data structure, just the comiler.
But what if you had a data structure like this:
var allOfTheLists = new Dictionary<T, List<T>>();
You could then break it out using something like this:
var explodedList = allOfTheLists.SelectMany((pair) => pair.Value.Select((item) => new { pair.Key, item}));
var grouping = explodedList.GroupBy((explodedItem) => explodedItem.item);