After answering this question I put together the following C# code just for fun:
public static IEnumerable<int> FibonacciTo(int max)
{
int m1 = 0;
int m2 = 1;
int r = 1;
while (r <= max)
{
yield return r;
r = m1 + m2;
m1 = m2;
m2 = r;
}
}
foreach (int i in FibonacciTo(56).Where(n => n >= 24) )
{
Console.WriteLine(i);
}
The problem is that I don't like needing to pass a max parameter to the function. Right now, if I don't use one the code will output the correct data but then appear to hang as the IEnumerable continues to work. How can I write this so that I could just use it like this:
foreach (int i in Fibonacci().Where(n => n >= 24 && n <= 56) )
{
Console.WriteLine(i);
}
You need to use a combination of SkipWhile and TakeWhile instead.
foreach (int i in Fibonacci().SkipWhile(n => n < 24)
.TakeWhile(n => n <= 56))
{
Console.WriteLine(i);
}
These are able to end loops depending on a condition; Where streams its input (filtering appropriately) until the input runs out (in your case, never).
I don't think this is possible unless you write your own LINQ provider. In the example you gave you are using LINQ to Objects which will need to completely evaluate the IEnumerable before it can apply a filter to it.
Related
Is there any way to clean up this type of loop using LINQ? I really think this method should be a one liner with LINQ. But I do not get it..
My Method looks like this:
int[] MakeList(int stepWidth)
{
var ret = new List<int>();
for (var i=0;i<360;i+=stepWidth)
{
ret.Add(i);
}
return ret.ToArray();
}
The only solution I could figure out was:
Enumerable.Range(0, 360).Where(x => x % stepWidth == 0).ToArray();
But this Enumerabl.Range(0,360) looks a little too crude to me :)
Combination of .Select and .TakeWhile could be one approach, but it looks very close to other approaches
var result = Enumerable.Range(0, int.MaxValue)
.Select(i => i * step)
.TakeWhile(i => i < 360)
.ToArray();
First: your code is nice and readable.
Second: don't be afraid of loops - loops perfectly show programmer intentions. If I had to change something, I would eliminate List<i>:
int[] MakeList(int stepWidth)
{
var length = (360 + stepWidth - 1) / stepWidth;
var ret = new int[length];
for (var i = 0; i < length; i++)
{
ret[i] = i * stepWidth;
}
return ret;
}
Third: if LINQ is used frequently, I would return IEnumerable<int> (see generators):
IEnumerable<int> MakeSequence(int step)
{
for (var i = 0; i < 360; i += step)
yield return i;
}
And use it as follows: MakeSequence(x).ToArray() or MakeSequence(x).[SomeLinqMethods].
I have made a code which basically compares two lists in C#. First list contains properties like this:
ItemID
TotalViews
First list lacks values for TotalViews so I'm assigning them from 2nd list which has these props:
ItemID
HitCount // this is property for TotalViews that needs to be assigned
The code is as following:
foreach (var item in parsedMerchantData)
{
var itemInB = HitCountItemIDS.FirstOrDefault(x => x.ItemID == item.ItemID);
if (itemInB != null)
{
if (itemInB.HitCount != -1)
{
item.TotalViews = itemInB.HitCount;
}
else
{
item.TotalViews = 0;
}
}
}
Is there any more efficient way to write this using LINQ or implementing a custom comparer which would work faster on larger lists that contains sometimes 100000 items in themselves?
This is like jdweng's answer, but slightly simpler and it won't throw an exception for missing item IDs:
var hitCountsById = HitCountItemIDS.ToDictionary(x => x.ItemID, x => x.HitCount);
foreach (var item in parsedMerchantData)
{
int hitCount;
// We don't care about the return value of TryGetValue here...
hitCountsById.TryGetValue(item.ItemID, out hitCount);
item.HitCount = hitCount == -1 ? 0 : hitCount;
}
This should be O(N+M) where N is the size of HitCountItemIDs and M is the size of parsedMerchantData... so should as the data gets bigger, it should grow more slowly than the merge-sort approach, and is definitely simpler code. (It doesn't require comparing item ID for ordering, either - just equality.)
Here is the pseudo-code:
var arr1 = parsedMerchantData.OrderBy(x => x.ItemID).ToArray();
var arr2 = HitCountItemID.OrderBy(x => x.ItemID).ToArray();
var i, j = 0;
while(i + j < arr1.Length() + arr2.Length()) // or similar condition
{
if (arr1[i].ItemID < arr2[j].ItemID) {
if (i < arr1.Length() - 1) {
i++;
}
continue;
}
if (arr1[i].ItemID > arr2[j].ItemID) {
if (j < arr2.Length() - 1) {
j++;
}
continue;
}
if (arr1[i].ItemID == arr2[j].ItemID) {
arr1[i].TotalViews = arr2[j].HitCount != -1 ? arr2[j].HitCount : 0;
}
// Make sure you do not let i and j grow higher then lengths of arrays
}
The idea is to apply MergeSort algorithms.
As for complexity, you spend O(n * log(n)) sorting each list then O(n) going trough them. The total is O(n * log(n)) and it is the fastest way I see.
Code would look like below. Not sure what the type of HitCountItemID is. If it is anonymous then just make 'var dict' :
Dictionary<string, ABC_TYPE> dict = HitCountItemID.GropupBy(x => x.ItemID, y => y).ToDictionary(x => x.Key, y => y.FirstOrDefault())
foreach (var item in parsedMerchantData)
{
var itemInB = dict[item.ItemID];
if (itemInB != null)
{
if (itemInB.HitCount != -1)
{
item.TotalViews = itemInB.HitCount;
}
else
{
item.TotalViews = 0;
}
}
}
I assume You are holding 2 lists during the program run/collecting data, so You can sort them during insertion. Or if they are in DB and there is an Index on the ID it migh also work.
If so, You should be able to do just one run through each array, which would optimize the program really high (now you got about n^2 complexity depending on values), after you change You would have n.
int i = 0, j = 0;
while( i < parsedMerchantData.Count && j < HitCountItemIDS.Count)
{
var item = parsedMerchantData[i];
var itemInB = HitCountItemIDS[j];
if (itemInB.ItemID == item.ItemID)
{
item.TotalViews = (itemInB.HitCount > 0) ? itemInB.HitCount : 0;
i++;
j++;
}
else if(itemInB.ItemID < item.ItemID)
i++;
else //itemInB.ItemID > item.ItemID
j++;
}
The code should look similar to the one above, You should add some more control about when it ends & what should happend with the rest values (this will stop once either i or j hit the end).
I made a function to generate the odd numbers:
static IEnumerable<int> OddNumbers()
{
int n = 1;
while (true)
yield return 1 + 2 * (n++ - 1);
}
How do I go through and filter this list? I am trying to remove all the multiples of a certain number factor, I wrote this:
using (var oddNumbers = OddNumbers().GetEnumerator())
{
oddNumbers.MoveNext();
int factor = oddNumbers.Current;
yield return factor;
oddNumbers = oddNumbers.Where(x => x % factor != 0);
}
but I get told that
The type arguments for method `System.Linq.Enumerable.Where<TSource>(
this System.Collections.Generic.IEnumerable<TSource>,
System.Func<TSource,bool>)' cannot be inferred from the usage.
Try specifying the type arguments explicitly`
To my understanding there is no need to access the enumerator directly, it can be done using Linq alone as follows.
var FilteredNumbers = OddNumbers().Where(x => x % factor != 0);
You can either use Linq:
// Initial generator
static IEnumerable<int> OddNumbers() {
for (int n = 1; ; n += 2) // for loop is far better than while here
yield return n;
}
...
var result = OddNumbers()
.Where(x => x % factor ! = 0);
Or modify the generator itself:
static IEnumerable<int> OddNumbersAdvanced(int factorToExclude = int.MinValue) {
for (int n = 1; ; n += 2)
if (n % factorToExclude != 0)
yield return n;
}
...
var result = OddNumbersAdvanced(factor);
To go through use foreach loop:
foreach (int item in result) {
//TODO: put relevant code here; do not forget to break the loop
}
Since you need that to generate sequence of lucky numbers, here is some code I wrote to do this with iterators. Note that it's very inefficient to do that this way, but hopefully you are doing this just for fun or for learning
static IEnumerable<int> LuckyNumbers(IEnumerable<int> all = null, int n = 2, int step = 0) {
if (step == 0) {
all = Enumerable.Range(1, int.MaxValue); // start with all numbers
yield return 1;
step++;
}
// apply a filter for current "n" (starting with 2)
var filtered = Filtered(all, n);
// get next item from the sequence (skip items first, because this sequence represents whole lucky number sequence, starting from 1)
var current = filtered.Skip(step).First();
yield return current;
step++;
// now recursive call back into LuckyNumber
foreach (var other in LuckyNumbers(filtered, current, step)) {
yield return other;
}
}
static IEnumerable<int> Filtered(IEnumerable<int> previous, int n) {
// filter out each n-th item
return previous.Where((x, i) => (i + 1)%n != 0);
}
Use like this:
foreach (var next in LuckyNumbers().Take(10)) {
Console.WriteLine(next);
}
Requirements:
Create a list of n sequential numbers starting at a.
Exclude number x.
This is the best I have right now, the problem being that it creates n + 1 numbers if x is not within the range.
var numbers = Enumerable
.Range(a, numberOfDataRowsToAdd + 1)
.Where(i => i != TechnicalHeaderRowIndex);
Example 1 should produce 0,1,2,3,4,5,6,7,8,9.
var a = 0;
var n = 10;
var x = 11;
Example 2 should produce 0,1,2,3,4,5,7,8,9,10.
var a = 0;
var n = 10;
var x = 6;
Here is a Fiddle that demonstrates Mark's answer.
How about
Enumerable.Range(a, n + 1)
.Where(i => i != x)
.Take(n);
My example, how it can be done without LINQ and extra loop iterations:
public static IEnumerable<int> GenerateNumbers(int a, int n, int x)
{
for (var i = 0; i < n; i++)
{
if (a == x)
{
i--;
a++;
continue;
}
yield return a++;
}
}
But if you don't want create new method for this purpose, Mark Sowul or Jakub Lortz answers are better.
The problem can be described as
Get n + 1 sequential numbers starting from a
If x is in the range, remove x, otherwise remove the maximum number from the list
Translated to C#
int numberToExclude = Math.Min(n + a, x);
var numbers = Enumerable.Range(a, n + 1).Where(i => i != numberToExclude);
It makes sense to generate only necessary values instead of generating n + 1 values and then remove x:
Enumerable.Range(a, n).Select(i => i < x ? i : i + 1);
Example 1: 0,1,2,3,4,5,6,7,8,9.
Example 2: 0,1,2,3,4,5,7,8,9,10.
You can drop the last if your enumerable count is bigger than numberOfDataRowsToAdd
Extension method:
public static IEnumerable<T> DropLast<T>(this IEnumerable<T> enumerable)
{
return enumerable.Take(enumerable.Count()-1);
}
Usage:
var numbers = Enumerable
.Range(a, numberOfDataRowsToAdd + 1)
.Where(i => i != TechnicalHeaderRowIndex);
if(numbers.Count() > numberOfDataRowsToAdd)
numbers = numbers.DropLast();
I don't see what really is the challenge - Linq shortest or fastest or just working. How about the natural (which should also be the fastest Linq based)
var numbers = a <= x && x < a + n ?
Enumerable.Range(a, x - a).Concat(Enumerable.Range(x + 1, a - x + n)) :
Enumarble.Range(a, n);
Say I have elements (X, Y, and Z) in a list, I have a function, that generates a percentage, of how much two objects resemble each other.
What I want to do, is run X against Y and Z using my compareElements, so:
compareElements(X,Y); // equals 55
compareElements(X,Z); // equals 60
Then Y against X and Z
compareElements(Y,X); // equals 55
compareElements(Y,Z); // equals 62
Then Z against Y and X
compareElements(Z,X); // equals 60
compareElements(Z,Y); // equals 62
Then, I return the highest value, which is 62.
Obviously, there's some repetition there, I don't need the repetition, but I'm not sure how to eliminate it.
How do I structure my LINQ query, or a function/algorithm to do this comparison on every element, without the repetition?
I'd prefer to use LINQ if I can, as I'm being passed an enumerable and the function returns before the list is actually enumerated, so we can save the cost of performing the compare, until the list is enumerated.
All I need is that highest value, of the compare functions, 62.
Note: My actual result set I'm working with averages between 3 and 10 elements in the list, that need to be ran through this compare function.
I'd be inclined to do it like this:
int count = list.Count;
var query = from index1 in Enumerable.Range(0, count)
from index2 in Enumerable.Range(index1 + 1, count - (index1 + 1))
select ComputeSimilarity(list[index1], list[index2]);
var maxSimilarity = query.Max();
I'm not sure I'm understanding you correctly, but try something like this:
public int compareElementList(List<Element> elements)
{
int result = 0;
for (int i = 0; i < elements.Count - 1; i++)
{
for (int q = i + 1; q < elements.Count; q++)
{
result = Math.Max(result, compareElements(elements[i], elements[q]));
}
}
return result;
}
This will eliminate the duplicate comparisons for you. It doesn't use LINQ, but I think it's still pretty readable.
UPDATE: Here is my version modified to handle IEnumerables. It varies from Jon Hanna's in that it doesn't create a new List, it just keeps track of two iterators.
public int compareElementEnumerable(IEnumerable<Element> elements)
{
int result = 0, i = 0, q = 1;
foreach (Element el in elements)
{
foreach (Element el2 in elements)
{
if (q > i)
{
result = Math.Max(result, compareElements(el, el2));
}
q++;
}
i++;
}
return result;
}
For the sake of readability, I would write an iterator block to generate the comparisons in a non-repetitive manner:
IEnumerable<Tuple<T, T>> GetComparisons<T>(IEnumerable<T> elements)
{
var visited = new List<T>();
foreach(T current in elements)
{
foreach(T previous in visited)
yield return new Tuple<T, T>(current, previous);
visited.Add(current);
}
}
Then you can do the following:
var highScore = GetComparisons(listOfElements)
.Select(x=>compareElements(x.Item1, x.Item2)
.Max();
(That said I prefer Smelch's suggestion for situations where there's no practical reason to use LINQ or iterators, such as having a need for composable routines.)
Don't know if it is what you are searching for, but I would try to use LINQ in this way:
var linq = from el1 in list
from el2 in list
where el1 != el2
select CompareFunction(el1, el2);
int max = linq.Max();
Comparison sample implementation:
int CompareFunction(string a, string b)
{
return a.Length - b.Length;
}
This way you compare each element against the other elements in the list (it is a sort of permutation I think) except itself, then select the comparison value and finally the highest value.
You could compile a list of the possible combinations you want to test into a List<Tuple<int, int>>
and then select the maximum
mylist.Select(i => new [] { Tuple.New(i.X, i.Y}, Tuple.New(i.X, i.Z), Tuple.New(i.Y, i.Z)})
.Max(t => compareElements(t.First, t.Second))
Pretty much the same as a couple given, but doesn't require one to assign to a list first.
List<Element> soFar = new List<Element>();
// If I expected a good few duplicate values, and if
// compareElements(x, x) isn't 100% - i.e. it's not a similarity
// check for example, then I'd use HashSet<Element> and skip
// when .Add() fails.
int result = 0;
foreach(Element el in sourceEnumeration)
{
for(int i = 0; i != soFar.Count; ++i)
{
int cmp = compareElements(el, soFar[i]);
if(cmp > result)
{
if(cmp == 100)
return 100;
cmp = result;
}
}
soFar.Add(el);
}
return result;
An unreadable LINQ implementation (may not compile, I haven't tested):
Enumerable.Range(0, listOfElements.Length).ToList().ForEach(i=>Enumerable.Range(i, listOfElements.Length-i-1).ToList().ForEach(j=>compareElements(listOfElements[i], listOfElements[j]))).Max();