I am squaring each integer in a List. Here is the code.
class SomeIntgs
{
List<int> newList = new List<int>();
public List<int> get()
{
IEnumerable<int> intrs = new int[] { 1, 2, 3, 4, 5, 6, 7, 8 };
newList.AddRange(intrs);
return newList;
}
}
I am getting error in Main()
SomeIntgs stg = new SomeIntgs();
var qry = from n in stg.get() where (P => P*P) select n;
Error : "Can not convert lambda expression to type bool ".
Help Please.
Also help me, how can i handle lambda in general context
You don't need the where, try this:
SomeIntgs stg = new SomeIntgs();
var qry = from n in stg.get() select n*n;
or
var qry = stg.get().Select(P => P*P);
Enumerable.Where is used to filter elements from a sequence - what you really want to do is project a new sequence of elements like I have shown above.
The lambda that the where clause takes specifies how you match an item from your IQueryable. Any member of the IQueryable that satisfies the expression you supply will be returned. (This is why your compiler is complaining about bools).
As others have mentioned, you can drop the where clause to square each item in the list.
var ints = new int []{1,2,3,4,5,6,7,8};
var squares = ints.Select(x => x*x);
var evenSquares = ints.Where(x => (x % 2) == 0).Select(x => x*x); // only square
//the even numbers in the list
SomeIntgs stg = new SomeIntgs();
var qry = from n in stg.get() select n*n;
Related
I like C# linq and also the extension methods style.
Here is a simple code to get how many times of each number is there in an array:
static void Main(string[] args)
{
int[] nums = { 1, 2, 2, 3, 3, 3 };
var groups = nums.GroupBy(n => n);
//var keynums = nums.Distinct();//ok
var keynums = Enumerable.Range(0, 10);//causes ArgumentNullException
var timesDict = keynums.ToDictionary(n => n,
n =>
groups.FirstOrDefault(g => g.Key == n)
//((groups.FirstOrDefault(g => g.Key == n))??what can be put here)
.Count());
foreach (var kv in timesDict)
{
Console.WriteLine($"{kv.Key}\t{string.Join(" ", kv.Value)}");
}
Console.ReadKey();
}
The code works, but if I want know the nums are always [0-9], and want to get how many times [0-9] appears (if not appears, the count should be 0).
So the code will get ArgumentNullException, which makes sense because FirstOrDefault gets null.
So to fix this, I want to use the ?? operator, and give it a default value. but I cannot think of how to construct such value.
How would you solve it? please do not use other styles such as if, select new {}.
How about using C#6 null-propagation like this?
groups.FirstOrDefault(g => g.Key == n)?.Count() ?? 0
if FirstOrDefault returns null, ?.Count() will not be evaluated anymore and not throw an exception.
You can use like this:
var higherLimits = new[] { 10, 20, 30 };
var ranges = items.GroupBy(item => higherLimits.First(higherLimits => higherLimits >= item));
This will avoid null issue altogether.
I'll give you my best attempt at understanding it and you let me know where I'm going wrong.
For simplicity, let's assume that we live in a word that only has
numbers 1, 2, 3, 4, 5
operators %, > with their usual precdence
I want to dissamble what happens when I do
List<int> All = new List<int> { 1, 2, 3, 4, 5 };
IEnumerable<int> Filtered = from i in All
where i % 2 == 1
orderby i descending
select i;
foreach ( var i in Filtererd )
{
Console.WriteLine(i);
}
What I understand first of all is that the query itself does not create a Ienumerable<int>; it creates and Expression Tree associated with the query. The elements returned by the query are yielded in an invisible function created by the compiler like
public static IEnumerable<int> MyInvisibleFunction ( List<int> Source )
{
foreach ( int i in Source.Reverse() )
{
if ( i % 2 == 1 )
{
yield return i;
}
}
}
(Of course that's kind of a weird example because Source.Reverse() is itself a query, but anyways ...)
Now I'm confused where expression tress come into play here. When I think of expression trees, I think of trees like
(3 % 1 > 0)
/ \
/ \
(3 % 1) > 0
/ \
3 % 1
in the small world I've created. But where does a tree like that come in to play in my LINQ query
from i in All
where i % 2 == 1
orderby i descending
select i
??? That's what I don't understand. I'm looking at the Expression class and I see how it could create the example tree I showed, but I don't see where it would come into play in my query.
I'll give you my best attempt at understanding it and you let me know where I'm going wrong.
OK.
What I understand first of all is that the query itself does not create a Ienumerable<int>;
This statement is completely wrong.
it creates and Expression Tree associated with the query.
This statement is also completely wrong.
The elements returned by the query are yielded in an invisible function created by the compiler
This statement is also completely wrong.
where does a tree like that come in to play in my LINQ query
It doesn't. Your query uses no expression trees.
I'm looking at the Expression class and I see how it could create the example tree I showed, but I don't see where it would come into play
It doesn't.
want to dissamble what happens when I do
List<int> All = new List<int> { 1, 2, 3, 4, 5 };
IEnumerable<int> Filtered = from i in All
where i % 2 == 1
orderby i descending
select i;
foreach ( var i in Filtererd )
Console.WriteLine(i);
Let's break it down. First the compiler turns that into
List<int> All = new List<int> { 1, 2, 3, 4, 5 };
IEnumerable<int> Filtered = All.Where(i => i % 2 == 1).OrderBy(i => i);
foreach ( var i in Filtererd )
Console.WriteLine(i);
Next the compiler does overload resolution and evaluates extension methods
List<int> All = new List<int> { 1, 2, 3, 4, 5 };
IEnumerable<int> Filtered =
Enumerable.OrderBy<int>(
Enumerable.Where<int>(All, i => i % 2 == 1)),
i => i));
foreach ( var i in Filtererd )
Console.WriteLine(i);
Next lambdas are desugared:
static bool A1(int i) { return i % 2 == 1; )
static int A2(int i) { return i }
...
List<int> All = new List<int> { 1, 2, 3, 4, 5 };
IEnumerable<int> Filtered =
Enumerable.OrderBy<int>(
Enumerable.Where<int>(All, new Func<int, bool>(A1))),
new Func<int, int>(A2)));
foreach (var i in Filtererd )
Console.WriteLine(i);
That is actually not how the lambdas are desugared exactly; they are also cached, but let's ignore that detail.
I assume that you do not want the foreach desugared. See the C# specification for details.
If you want to know what Where and OrderBy do, read the source code.
Expression trees don't come into play in your query, because your source is a regular in-memory list. – Theodoros Chatzigiannakis
This is true.
There is no invisible iterator function being generated. Your query translates to:
List<int> All = new List<int> { 1, 2, 3, 4, 5 };
IEnumerable<int> Filtered =
All
.Where(i => i % 2 == 0)
.OrderByDescending(i => i);
There is no need for custom iterators. The language just calls the existing library functions.
This is the same for IQueryable except that the lambda arguments are not passed as delegates but as expression trees.
You can see this in action by commenting in the AsQueryable() call here.
I am having trouble figuring out how to do something like the following. This is purely pseudocode:
decimal totalActiveCost = (from i in _context.KeyActives
where i.Pk in (active1fk, active2fk, active3fk, active4fk, active5fk, keyActiveFk)
select sum(i.Cost)...`
Then summing the i.Cost. So basically, I need to return the i.Cost for each "Active" - so, for example, say active1fk is 1, active2fk is 2, and so on. I need to get the Cost for each of these and sum them up.
You can have your active foreign keys in a List<T> like:
List<int> activeFks = new List<int> {1,2,3,4,5,};
var sum = (from i in _context.KeyActives
where activeFks.Contains(i.PK)
select i.Cost).Sum();
Or with a method syntax:
var sum = _context.KeyActives
.Where(r=> activeFks.Contains(r.PK))
.Sum(r=> r.Cost);
Something like this will work:
List<Int> ids = new List<int>();
ids.Add(1);
ids.Add(2);
var result = _context.KeyActives.
Where(c => ids.Contains(c.id))
.Sum(c => c.Cost);
var ids = new List<int> {active1fk, active2fk, active3fk, active4fk, active5fk, keyActiveFk};
var sum = (from i in _context.KeyActives
where ids.Contains(i.Pk)
select i).Sum(a=> a.Cost);
(See my code snippet below) I want to find all items of coll1 that matched to items of coll2 (number of items of coll2 <= number of items of coll1) and put the query result in coll3. How to achieve it using linq and lambda expression?
Surely, I can simply copy coll2 to coll3 :-) but that is not my goal. I want to know the ways using linq and lambda to replace such conventional logic construct. Thank you in advance.
var coll1 = new List<int>() { 1, 2, 3, 4, 5 };
var coll2 = new List<int>() { 2, 4 };
var coll3 = new List<int>();
foreach ( var selected in coll2 )
{
foreach ( var item in coll1 )
{
if ( selected == item )
{
coll3.Add(item);
}
}
}
You can use Intersect
coll1.Intersect(coll2);
But this wont work as expected(see King King's comment)..You can instead do this
coll2.Where(x=>coll1.Any(y=>x==y));
coll3 = coll1.Where(i => coll2.Contains(i)).ToList();
Update. A little bit simpler, as suggested in comments:
coll3 = coll1.Where(coll2.Contains).ToList();
As a first step, you can use a where clause to make your code more readable :
var coll1 = new List<int>() { 1, 2, 3, 4, 5 };
var coll2 = new List<int>() { 2, 4 };
var coll3 = new List<int>();
foreach (var selected in coll2)
{
coll3.AddRange(coll1.Where(item => selected == item));
}
Use Intersect: http://msdn.microsoft.com/en-us/library/bb460136.aspx
var coll3 = coll1.Intersect(coll2)
You could do this; not sure if it's more readable tho!
var coll3 = (from selected in coll2
from item in coll1
where selected == item
select item).ToList();
If you do not want to directly assign the result to your list, you could add 'ForEach' to your Linq statement:
coll1.Where(i => coll2.Contains(i)).ToList().ForEach(i => coll3.Add(i));
You might want to check for Distinct though
I have two lists:
List<int> data1 = new List<int> {1,2,3,4,5};
List<string> data2 = new List<string>{"6","3"};
I want do to something like
var newData = data1.intersect(data2, lambda expression);
The lambda expression should return true if data1[index].ToString() == data2[index]
You need to first transform data1, in your case by calling ToString() on each element.
Use this if you want to return strings.
List<int> data1 = new List<int> {1,2,3,4,5};
List<string> data2 = new List<string>{"6","3"};
var newData = data1.Select(i => i.ToString()).Intersect(data2);
Use this if you want to return integers.
List<int> data1 = new List<int> {1,2,3,4,5};
List<string> data2 = new List<string>{"6","3"};
var newData = data1.Intersect(data2.Select(s => int.Parse(s));
Note that this will throw an exception if not all strings are numbers. So you could do the following first to check:
int temp;
if(data2.All(s => int.TryParse(s, out temp)))
{
// All data2 strings are int's
}
If you have objects, not structs (or strings), then you'll have to intersect their keys first, and then select objects by those keys:
var ids = list1.Select(x => x.Id).Intersect(list2.Select(x => x.Id));
var result = list1.Where(x => ids.Contains(x.Id));
From performance point of view if two lists contain number of elements that differ significantly, you can try such approach (using conditional operator ?:):
1.First you need to declare a converter:
Converter<string, int> del = delegate(string s) { return Int32.Parse(s); };
2.Then you use a conditional operator:
var r = data1.Count > data2.Count ?
data2.ConvertAll<int>(del).Intersect(data1) :
data1.Select(v => v.ToString()).Intersect(data2).ToList<string>().ConvertAll<int>(del);
You convert elements of shorter list to match the type of longer list. Imagine an execution speed if your first set contains 1000 elements and second only 10 (or opposite as it doesn't matter) ;-)
As you want to have a result as List, in a last line you convert the result (only result) back to int.
public static List<T> ListCompare<T>(List<T> List1 , List<T> List2 , string key )
{
return List1.Select(t => t.GetType().GetProperty(key).GetValue(t))
.Intersect(List2.Select(t => t.GetType().GetProperty(key).GetValue(t))).ToList();
}