Linq Index question - c#

Can I write code like this with index
var someArray = new List<int>(){1,2,3,4,5};
var resultArray = someArray.Where((num, index) => index % 2 == 0);
like
var resultArray = from num in someArray...

I suppose you are asking "can I use query expression syntax to get at the overload of Where that provides the item index, in the way that I can using fluent method-chaining syntax".
The answer is no.
As seen in the docs for the no-index-parameter overload of Where :
In query expression syntax, a where clause translates to an invocation of Where<TSource>(IEnumerable<TSource>, Func<TSource, Boolean>).

No, you cannot. There is no equivalent for the Where extension method allowing you to use the index using LINQ syntax.

The only way seems to be to hack around the problem:
var count = 0;
var resultArray = from num in someArray
let index = count++
where index % 2 == 0
select num;
Probably better to use the other syntax.

Related

Change value of each element by linq

Is it possible to do sth like this in LINQ:
int[] d = new int[c.Length + 1];
int e = 1;
d.ToList().ForEach(r =>
{
r = e;
e++;
});
?.
When I did this, it returned me sequence of zeros.
Regards.
Yes, it would, for two reasons:
You're creating a copy of the original array as a List<int>, and then trying to modify the List<int>. That wouldn't modify the array.
Your lambda expression changes the value of the parameter, that's all. It doesn't modify the list.
Basically, LINQ is for querying. Don't even bother trying to do this: use a for loop if you want to modify the collection.
However, if your aim is to produce an array of 1...(c.Length+1), just use Enumerable.Range:
var array = Enumerable.Range(1, c.Length + 1).ToArray();

count objects that meet certain condition in List-collection

I want to count the occurences of objects within a List<T> that match a certain condition.
For example like this
int List<T>.Count(Predicate<T> match)
So for example if have a list of chores, I can see how many are overdue.
int overdue = listOfChores.Count((element) => { return element.DueDate <= DateTime.Today; });
I know that does not exist and so far I solve problems like that in the following way:
int overdue = listOfChores.FindAll([...]).Count;
However that allocates and initializes a new List etc. only to get the count.
A way to do this with less allocation overhead etc.:
int good = 0;
foreach(chore element in listOfChores)
if(element.DueDate <= DateTime.Today)
good++;
The last approach can also be exandend to count several conditions without iterating over the loop more than once. (I already found that getting the count property only takes O(1), but making the List to count from still eats a lot of time)
int a = 0;
int b = 0;
foreach(chore element in listOfChores)
if(element.CondA)
a++;
if(element.CondB)
b++;
Given this I could even imagine something like
int[] List<T>.Count(Predicate<T>[] matches)
My question(s):
Is there such a thing, just I haven't found it yet?
If not: What would be way to implement such functionality?
EDIT :
Adding LINQ looks like it fixes it.
You just have your syntax slightly off. This is how to use Count :
int overdue = listOfChores.Count(element => element.DueDate <= DateTime.Today);
If you already have a Predicate<T> and want to pass it to Count just call it like a function:
Predicate<Chore> p = (element) => element.DueDate <= DateTime.Today;
int overdue = listOfChores.Count(element => p(element));
There's is a count method using a predicate : see Enumerable.Count Method (IEnumerable, Func)
Note that this method is an extension method and you can use it only if you add a reference to the System.Linq namespace.

Convert IEnumerable<byte[]> to byte[]

var r = from s in tempResult
select Encoding.GetEncoding("iso-8859-1").GetBytes(s);
I understand, this returns IEnumerable<byte[]>, but I looking for LINQ way to convert the whole IEnumerable<byte[]> to byte[].
None of the answers provided so far will work, because they will convert the IEnumerable<byte[]> to byte[][]. If your goal is to take all of the arrays in the enumerable and produce one big array, try this:
byte[] result = r.SelectMany(i => i).ToArray();
See this ideone example.
Note that this is not the most efficient way to do this. It would be faster to convert the original query result to a list, then compute the sum of the array lengths. Once that is done, you can allocate the final array immediately, then make one more pass over the result list and copy each result array's contents into the larger array.
The above LINQ query definitely makes this task easy, but it will not be fast. If this code becomes a bottleneck in the application, consider rewriting it this way.
I might as well provide an example of a more efficient implementation:
public static T[] JoinArrays<T>(this IEnumerable<T[]> self)
{
if (self == null)
throw new ArgumentNullException("self");
int count = 0;
foreach (var arr in self)
if (arr != null)
count += arr.Length;
var joined = new T[count];
int index = 0;
foreach (var arr in self)
if (arr != null)
{
Array.Copy(arr, 0, joined, index, arr.Length);
index += arr.Length;
}
return joined;
}
Note that whatever enumerable you pass in will be enumerated twice, so it would be a good idea to pass in a list or an array instead of a query, if that query is expensive.
Are you sure that's what you want to do? This code already returns a byte array:
Encoding.GetEncoding("iso-8859-1").GetBytes(s);
In any case, if you want to convert the enumeration to an array, you would do so like this:
var myArray = (from s in tempResult
select Encoding.GetEncoding("iso-8859-1").GetBytes(s)).ToArray();
EDIT
After your edit, I see I've misunderstood what you're trying to accomplish. If I understand correctly now, you're trying to get a byte array containing concatenated strings in tempResult? I would so it like this:
var concatenated = String.Join("", tempResult.ToArray());
var byteArray = Encoding.GetEncoding("iso-8859-1").GetBytes(concatenated);
What about ToArray extension method?
byte[] array = r.SelectMany(a => a).ToArray();
var r = (from s in tempResult
select Encoding.GetEncoding("iso-8859-1").GetBytes(s)
).ToArray();

Why is this delegate syntax "legal"?

I am reading about anonymous methods and am trying to wrap my head around this example:
List<int> evenNumbers = list.FindAll(delegate(int i)
{ return (i % 2) == 0; } )
Why is delegate(int i) legal? You aren't having to declare new delegate void or anything like that.
Is that what is meant by anonymous method? Is this the added syntactic sugar that allows for anonymous methods?
It's legal because of what you suspect, it's creating an anonymous delegate/method.
An alternative (using the lambda operator =>) would be:
List<int> evenNumbers = list.FindAll((i) => ((i % 2) == 0));
or
List<int> evenNumbers = list.FindAll(i => i % 2 == 0);
See Lambda Expressions for further reading.
If you decompose the statement a little, hopefully it will be more obvious - this is the equivalent code.
Predicate<int> test = delegate(int i)
{
return (i % 2) == 0;
};
List<int> evenNumbers = list.FindAll(test);
As you can see it created an anonymous delegate (that the compiler will turn into a method behind the scenes)
Personally I've always found the "inline" anonymous delegate syntax to cloud the issue more than add clarity whereas the same construct built using a lambda expression, once you are used to the syntax, adds clarity
List<int> evenNumbers = list.FindAll(i => i % 2 == 0);
in this code it seems like passing a method into a method using a delegate.

How to Compare Values in Array

If you have a string of "1,2,3,1,5,7" you can put this in an array or hash table or whatever is deemed best.
How do you determine that all value are the same? In the above example it would fail but if you had "1,1,1" that would be true.
This can be done nicely using lambda expressions.
For an array, named arr:
var allSame = Array.TrueForAll(arr, x => x == arr[0]);
For an list (List<T>), named lst:
var allSame = lst.TrueForAll(x => x == lst[0]);
And for an iterable (IEnumerable<T>), named col:
var first = col.First();
var allSame = col.All(x => x == first);
Note that these methods don't handle empty arrays/lists/iterables however. Such support would be trivial to add however.
Iterate through each value, store the first value in a variable and compare the rest of the array to that variable. The instant one fails, you know all the values are not the same.
How about something like...
string numArray = "1,1,1,1,1";
return numArrray.Split( ',' ).Distinct().Count() <= 1;
I think using List<T>.TrueForAll would be a slick approach.
http://msdn.microsoft.com/en-us/library/kdxe4x4w.aspx
Not as efficient as a simple loop (as it always processes all items even if the result could be determined sooner), but:
if (new HashSet<string>(numbers.Split(',')).Count == 1) ...

Categories

Resources