Can you combine multiple lists with LINQ? - c#

Say I have two lists:
var list1 = new int[] {1, 2, 3};
var list2 = new string[] {"a", "b", "c"};
Is it possible to write a LINQ statement that will generate the following list:
var result = new []{
new {i = 1, s = "a"},
new {i = 1, s = "b"},
new {i = 1, s = "c"},
new {i = 2, s = "a"},
new {i = 2, s = "b"},
new {i = 2, s = "c"},
new {i = 3, s = "a"},
new {i = 3, s = "b"},
new {i = 3, s = "c"}
};
?
Edit: I forgot to mention I didn't want it in query syntax. Anyway, based on preetsangha's answer I've got the following:
var result = list1.SelectMany(i => list2.Select(s => new {i = i, s = s}));

var result = from l1 in list1
from l2 in list2
select new { i = l1, s = l2};

preetsangha's answer is entirely correct, but if you don't want a query expression then it's:
var result = list1.SelectMany(l1 => list2, (l1, l2) => new { i = l1, s = l2} );
(That's what the compiler compiles the query expression into - they're identical.)

Related

How to combine multiple lists using LINQ lambda

I have two lists:
list1 = [a,b,c,4]
list2 = [1,23,5,6]
Now I need to create an anonymous object using linq lambda.
Something like.
list1 = DataTable.AsEnumerable().toList();
list2 = DataTable.AsEnumerable().toList();
var result = list1.Where(x => x.Field<int>(1) == 2018).Select(x => new[] {
new {x = "XYZ", y = x[0], z = list2[0]},
....}
}
How do I go about doing this?
You need Zip Linq method, consider this example:
int[] list1 = {1, 2, 3};
string[] list2 = {"a", "b", "c"};
var result = list1.Zip(list2, (i, s) => new {y = i, z = i});
Your code is fine, it just needs some small fixes:
string [] list1 = { "a", "b", "c", "4" };
int[] list2 = { 1, 23, 5, 6 };
object[] list3 = { "test", DateTime.Now, 56 };
var result = list1.Where(x => x == "a").Select(x =>
new { x = "XYZ", y = x[0], z = list2[0], t = list3[1] }).ToList();

get common elements in lists in C#

I have two sorted lists as below:
var list1 = new List<int>() { 1, 1, 1, 2, 3 };
var list2 = new List<int>() { 1, 1, 2, 2, 4 };
I want the output to be: {1, 1, 2}
How to do this in C#?
Is there a way using Linq?
Use Intersect:
var commonElements = list1.Intersect(list2).ToList();
The extra 1 means you can't use Intersect because it returns a set.
Here's some code that does what you need:
var list1 = new List<int>() { 1, 1, 1, 2, 3 };
var list2 = new List<int>() { 1, 1, 2, 2, 4 };
var grouped1 =
from n in list1
group n by n
into g
select new {g.Key, Count = g.Count()};
var grouped2 =
from n in list2
group n by n
into g
select new {g.Key, Count = g.Count()};
var joined =
from b in grouped2
join a in grouped1 on b.Key equals a.Key
select new {b.Key, Count = Math.Min(b.Count, a.Count)};
var result = joined.SelectMany(a => Enumerable.Repeat(a.Key, a.Count));
CollectionAssert.AreEquivalent(new[] {1, 1, 2}, result);
This works nicely:
var list1 = new List<int>() { 1, 1, 1, 2, 3 };
var list2 = new List<int>() { 1, 1, 2, 2, 4 };
var lookup1 = list1.ToLookup(x => x);
var lookup2 = list2.ToLookup(x => x);
var results = lookup1.SelectMany(l1s => lookup2[l1s.Key].Zip(l1s, (l2, l1) => l1));
While both #Austin Salonen's solution and #Enigmativity's solution work for any given lists, neither take advantage of OP's condition that the lists are sorted.
Given that both lists will be ordered we can do a search in O(n + m) time where n and m are the length of each list. Not entirely sure what the previous solutions big o performance is, but it's definitely slower then O(n + m).
Basically we just walk both lists, moving one or both enumerators based on a comparison check.
var results = new List<int>();
var e1 = list1.GetEnumerator();
var e2 = list2.GetEnumerator();
var hasNext = e1.MoveNext() && e2.MoveNext();
while (hasNext) {
var value1 = e1.Current;
var value2 = e2.Current;
if (value1 == value2) {
results.Add(value1);
hasNext = e1.MoveNext() && e2.MoveNext();
} else if (value1 < value2) {
hasNext = e1.MoveNext();
} else if (value1 > value2) {
hasNext = e2.MoveNext();
}
}
That's it! results will be an empty list if no matches are found.
Note this assumes both lists are in ascending order. If it's descending, just flip the < and > operators.
I am late in answering this question, this might help future visitors.
List<int> p = new List<int> { 1, 1, 1, 2, 3 };
List<int> q = new List<int> { 1, 1, 2, 2, 4 };
List<int> x = new List<int>();
for (int i = 0; i < p.Count; i++ )
{
if (p[i] == q[i])
{
x.Add(p[i]);
}
}

Problem transforming dictionary with Linq

I've got a dictionary laid out like so:
Dictionary<string, List<Series>> example = new Dictionary<string, List<Series>>();
example.Add("Meter1",new List<Series>(){ new Series{ name="Usage", data = new double[] {1,2,3}},
new Series{ name = "Demand", data= new double[]{4,5,6}}});
example.Add("Meter2", new List<Series>(){ new Series{ name="Usage", data = new double[] {1,2,3}},
new Series{ name = "Demand", data= new double[]{4,5,6}}});
What I need is:
Dictionary<string, List<Series>> exampleResult = new Dictionary<string, List<Series>>();
exampleResult.Add("Usage", new List<Series>(){ new Series{ name="Meter1", data = new double[] {1,2,3}},
new Series{ name = "Meter2", data= new double[]{1,2,3}}});
exampleResult.Add("Demand", new List<Series>(){ new Series{ name="Meter1", data = new double[] {4,5,6}},
new Series{ name = "Meter2", data= new double[]{4,5,6}}});
That is, the dictionary projected "sideways", with the name of each Series as the key in the new dictionary, with the key of the old dictionary used as the name of the series.
Here's the series class...
public class Series
{
public string name { get; set; }
public double[] data { get; set; }
}
Sorry if I am not expressing this problem clearly, please ask any questions you'd like, and thanks in advance for any help...
EDITED TO ADD EXAMPLE
Create a grouping and then select out the new keys and values to create a dictionary. Like this:
// source data
var d = new Dictionary<string, Series[]>
{
{
"key1", new[]
{
new Series
{
name = "Usage",
data = new double[] {1, 2, 3}
},
new Series
{
name = "Demand",
data = new double[] {4, 5, 6}
}
}
},
{
"key2", new[]
{
new Series
{
name = "Usage",
data = new double[] {1, 2, 3}
},
new Series
{
name = "Demand",
data = new double[] {4, 5, 6}
}
}
}
};
// transform
var y = (
from outer in d
from s in outer.Value
let n = new
{
Key = s.name,
Series = new Series
{
name = outer.Key,
data = s.data
}
}
group n by n.Key
into g
select g
).ToDictionary(g1 => g1.Key,
g2 => g2.Select(g3 => g3.Series).ToArray());
/* results:
var y = new Dictionary<string, Series[]>
{
{
"Usage",
new[]
{
new Series
{
name = "key1",
data = new double[] { 1, 2, 3 }
},
new Series
{
name = "key2",
data = new double[] { 1, 2, 3 }
}
}
},
{
"Demand",
new[]
{
new Series
{
name = "key1",
data = new double[] {4, 5, 6},
},
new Series
{
name = "key2",
data = new double[] {4, 5, 6}
}
}
}
};
*/
Try this:
example
.SelectMany(x => x.Value
.Select(y => y.name)
).Distinct()
.ToDictionary(
x => x,
x => example
.SelectMany(y => y.Value
.Where(z => z.name == x)
.Select(z => new Series{ name = y.Key, data = z.data })
).ToList()
)

C# - Creating array where the array value has multiple objects and each one has a value too

I have just recently been doing something in C#, i would like to know how to do something like this.
Array[0] =
Array['Value'] = 2344;
Array['LocationX'] = 0;
Array['LocationY'] = 0;
Array[1] =
Array['Value'] = 2312;
Array['LocationX'] = 2;
Array['LocationY'] = 1;
Array[2] =
Array['Value'] = 2334;
Array['LocationX'] = 4;
Array['LocationY'] = 3;
The data it self its not important, the thing is that i know how to do this in PHP. But in C# i don't, and I've tried some ways and no luck.
In PHP i could just do something like this:
$Array[0]->Value = 2344;
$Array[0]->LocationX = 0;
$Array[0]->LocationY = 0;
And those values would be added to the Array.
In C# i've tried this and doesn't work that way.
Could someone enlighten me in how to do this in C#?
Thanks.
Well, you could have an array of instances of a class that you write like so:
public class DataForArray
{
public int Value { get; set; }
public int LocationX { get; set; }
public int LocationY { get; set; }
}
Then something like this:
DataForArray[] array = new DataForArray[10];
array[0] = new DataForArray();
array[0].Value = 2344;
etc...
Either write a class or struct to hold Value, LocationX and LocationY.
struct Foo
{
Foo(value, x, y)
{
Value = value;
LocationX = x;
LocationY = y;
}
Foo() {}
int Value;
int LocationX;
int LocationY;
}
Foo[] f = new []
{
new Foo(1, 2, 3),
new Foo(2, 3, 4)
}
or alternatively initialize the array this way:
Foo[] f = new []
{
new Foo() { Value = 1, LocationX = 2, LocationY = 3 },
new Foo() { Value = 4, LocationX = 5, LocationY = 6 },
}
Or use an Array of Dictionary<string, int>.
Dictionary<string, int>[] array = new []
{
new Dictionary<string, int>() {{ "Value", 1 }, {"LocationX", 2}, {"LocationY", 3 }},
new Dictionary<string, int>() {{ "Value", 4 }, {"LocationX", 5}, {"LocationY", 6 }}
}
Which is only recommended if it needs to be dynamic (means: you want to have different values in each element of the array or your keys are in strings, not known at compile-time.) Unless it is just hard to maintain.
in C#, you can try something like this
// initialize array
var list = new[]
{
new {Value = 2344, LocationX = 0, LocationY = 0},
new {Value = 2312, LocationX = 2, LocationY = 4},
new {Value = 2323, LocationX = 3, LocationY = 1}
}.ToList();
// iterate over array
foreach (var node in list)
{
var theValue = node.Value;
var thePosition = new Point(node.LocationX, node.LocationY);
}
// iterate over array with filtering ( value > 2300 )
foreach (var node in list.Where(el => el.Value > 2300))
{
var theValue = node.Value;
var thePosition = new Point(node.LocationX, node.LocationY);
}
// add again
list.Add(new { Value = 2399, LocationX = 9, LocationY = 9 });
Here is a link that details the use of Multidimensional arrays
http://msdn.microsoft.com/en-us/library/aa288453(VS.71).aspx
You can use anonymous type in C# like that:
var arr = new[] {
new{Value = 1, LocationX = 2, LocationY = 3},
new{Value = 1, LocationX = 2, LocationY = 3},
new{Value = 1, LocationX = 2, LocationY = 3},
new{Value = 1, LocationX = 2, LocationY = 3},
new{Value = 1, LocationX = 2, LocationY = 3} };
Only one problem is that properties in anonymous type are read-only. So You can't do something like that:
arr[1].Value = 2

Filtering in LINQ

From the given setup
IEnumerable<int> one = new int[] { 1, 2, 3, 4, 5, 6, 7 };
IEnumerable<int> two = new int[] { 12, 34, 56, 7, 8 };
MySet[] sets
= new MySet[]
{
new MySet{ MySetID =100, MySubSet=new MySubSet{SubSet=new List<int>(one),
SubSetID=1212}},
new MySet{ MySetID =101, MySubSet=new MySubSet{SubSet=new List<int>(two),
SubSetID=1414}}
};
How can i filter out even numbers from "SubSet"s
var GetSet =
from mysets in sets
where (P => mysets.MySubSet.SubSet.FindAll(???? ))
select mysets;
Is this what you want? Your question is rather confusingly worded, but I believe you are looking for something like this:
var query = from mySet in sets
select new MySet {
MySetID = mySet.ID,
MySubSet = new MySubSet {
SubSet = mySet.MySubSet.SubSet.Where(p => p % 2 == 0).ToList(),
SubSetID = mySet.MySubSet.SubSetID
}
};
So I am interpreting your question to mean that you want to filter out the even numbers from MySubSet.SubSet in each instance of MySet.

Categories

Resources