Nice, clean cross join in Linq using only extension methods [duplicate] - c#

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

Related

Multiply column major matrix linq

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();

Apply SelectMany to three or more sequences

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
*/

Easy way to GroupBySubElement on a collection in LINQ?

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

Convert List<double[]> to double[,]

Say I have a
List<double[]> x = new List<double[]>();
double[] item = new double[] {1.0,2.0,3.0};
x.add(item);
etc...
Is there a faster/cleaner way to get this into a double[,] then looping it:
double[,] arr = new double[x.Count,3];
for (row = 0; row < x.Count; row++)
{
for (col = 0; col < 3; col++)
arr[row,col] = x[row][col];
}
Thanks.
No, there isn't.
Multi-dimensional arrays are strange beasts and are not widely accepted or used in the BCL.
They're also slow and should be avoided where possible.
Because I felt like it, I solved this using LINQ, however, it's hardly any cleaner. In fact, I'd argue it's less clear, but it'd danm neat :)
// Input
List<double[]> a = new List<double[]>() {
new double[]{ 1.0, 2.0, 3.0 },
new double[]{ 4.0, 5.0, 6.0 },
new double[]{ 7.0, 8.0, 9.0 }
};
// Output
var b = a.Select((item, index) => new
{
Items = item.Select((inner, inIndex) => new { Inner = inner, Y = inIndex }),
X = index
})
.SelectMany(item => item.Items, (i, inner) => new { Value = inner.Inner, X = i.X, Y = inner.Y })
.Aggregate(new double[a.Count, a.Max(aa => aa.Length)], (acc, item) => { acc[item.X, item.Y] = item.Value; return acc; })
Note: This also works for arbitrarily sized inner double[] arrays, but there will be empty spots.
So yes, there's another way of doing it, but it's not a better way :)
There is always the var_export function?

LINQ dependent calculation assignment

I'm using the following pattern in C#:
IList<foo> x = y.Select(a => new foo
{
b = Calc1(),
c = Calc2()
}).ToList();
foreach(foo f in x)
{
f.d = b / c;
}
What I would like to do though is:
IList<foo> x = y.Select(a => new foo
{
b = Calc1(),
c = Calc2()
d = b / c;
}).ToList();
So the question is: How can you modify this pattern to allow the assignment of a value that is dependent on other values being calculated during the assignment?
(Somebody will probably point out that d should be a property that does the calculation and return a value. This is a contrived example. Assume that the value of d is calculated using other values in addition to c & b which are not available later.)
If you expand this to use the full LINQ syntax:
IList<foo> x = (from a in y
let bq = Calc1()
let cq = Calc2()
select new foo {
b = bq,
c = cq,
d = bq / cq
}).ToList();
This will get you what you want.
There was an answer recommending you repeat your method calls (ie, d = Calc1() / Calc2()) - but I would recommend against this, considering it may be possible that Calc1() and Calc2() are expensive operations, and needlessly performing them twice may have performance implications.
You can't re-use initialized properties in an initializer.
I like Erik's technique. If the query expression syntax is a bother, you can use a full-on anonymous method.
List<int> y = new List<int>() { 1, 2, 3, 4 };
var x = y.Select(a =>
{
int b = a + 1;
int c = a + 2;
int d = b / c;
return new { b = b, c = c, d = d };
});

Categories

Resources