|
Thanks, again !
A few gaps in (my understanding of) the puzzle:
1) "TryGetNonEnumeratedCount ... in the case that the enumerable doesn't already know its count, instead of falling back to counting elements one-by-one (as Count does), it just gives up"
If an IEnumerable "knew" its count ... is that a contradiction in terms ? Clearly, some collections "know" their count, because it is a Property not a method.. But, a generic IEnumerable created at run-time ?
2) "In some cases Count is actually more efficient"
fascinating; I try to imagine a case of a generic IEnumerable where Count() would be more efficient ... but, draw a blank
3) if you had a function that returned a generic IEnumerable, and in that Function you used Count(): would there be any structural differences between that returned result and a returned result IEnumerable you had never used Count on.
4) comparing a a generic IEnumerable you used Count() on with one you used Any() on: would there be any structural differences ?
«The mind is not a vessel to be filled but a fire to be kindled» Plutarch
|
|
|
|
|
BillWoodruff wrote: If an IEnumerable "knew" its count ... is that a contradiction in terms ?
Not really. For example, a List<T> is also an IEnumerable<T> ; the List<T> "knows" its count.
The TryGetNonEnumeratedCount method simply attempts to cast the IEnumerable<T> to a few "pre-counted" interfaces at run-time, and returns the Count property from the first one that succeeds. You can see the source code on GitHub:
runtime/Count.cs at 57bfe474518ab5b7cfe6bf7424a79ce3af9d6657 · dotnet/runtime · GitHub[^]
It tries ICollection<T> , IIListProvider<T> , and the non-generic ICollection . That should cover most cases, although it notably doesn't try the IReadOnlyCollection<T> introduced in .NET 4.5 - I can't find an official comment, but this SO thread[^] discusses that.
You can see the original proposal for this method on the runtime repository:
Non-enumerating Count Linq Method · Issue #27183 · dotnet/runtime · GitHub[^]
"These people looked deep within my soul and assigned me a number based on the order in which I joined."
- Homer
|
|
|
|
|
Thanks,Richard Deeming wrote: a List<T> is also an IEnumerable<T>; the List<T> "knows" its count. i find this a specious comparison, in the context of this thread; i would distinguish between an IEnumerable created at run-time that has been "topped up" in code, and a List that has been initialized, and had values added.
With 'List 'Count is a Property, with 'IEnumerable 'Count() is a method call that iterates over the 'IEnumerable using 'MoveNext ... if the Enumerable is not other certain Types, like an IList.Richard Deeming wrote: The TryGetNonEnumeratedCount method simply attempts to cast the IEnumerable<T> to a few "pre-counted" interfaces The source for IEnumerable.Coubt() uses the same short-circuiting behavior.
«The mind is not a vessel to be filled but a fire to be kindled» Plutarch
|
|
|
|
|
BillWoodruff wrote: I find this a specious comparison, in the context of this thread
Not sure I follow you here. You're writing code which can operate on an instance of any class that implements IEnumerable<T> . List<T> is such a class.
Your code wants to get the number of items in the source sequence, but only if that operation doesn't involve iterating over the entire collection. If the method was passed a List<T> , you can do it. If it was passed the result of an iterator method (for example), it can't.
It's all about examining the run-time type of the variable to access properties that aren't available on the compile-time type. From a purist perspective, that's not a good approach. But from a practical perspective, there are times when it's useful.
BillWoodruff wrote: The source for IEnumerable.Coubt() uses the same short-circuiting behavior.
The difference is, if the value passed in doesn't match one of the specific interfaces, Enumerable.Count(IEnumerable<T>) will proceed to enumerate the entire sequence, whereas TryGetNonEnumeratedCount will give up.
For example, given:
public static IEnumerable<int> Answers()
{
while (true)
{
yield return 42;
}
} using:
if (Answers().TryGetNonEnumeratedCount(out int count))
{
Console.WriteLine(count);
}
else
{
Console.WriteLine("Nope");
} will output "Nope", whereas:
int count = Answers().Count();
Console.WriteLine(count); will never return.
"These people looked deep within my soul and assigned me a number based on the order in which I joined."
- Homer
|
|
|
|
|
Hi, Richard, thanks !
Perhaps i have not emphasized enough that this thread is about a not-iterated over IEnumerable.Richard Deeming wrote: Not sure I follow you here. You're writing code which can operate on an instance of any class that implements IEnumerable<T>. List<T> is such a class. Yes, the input to the first Func<IEnumerable<T>, IEnumerable<T>> in the series is an instance of a collection: the subsequent Func<IEnumerable<T>, IEnumerable<T>> calls take as input the previously created IEnumerable<T> results.
Because getting the count is not necessary here, 'Any() appears to be the only possibly efficient way to see if the IEnumerable is not "empty." It will have to do
i may be too "picky" here (based on how i see students respond to this topic) when i express my semantic discomfort with the equating of an instance of List<T> with IEnumerable<T> /
«The mind is not a vessel to be filled but a fire to be kindled» Plutarch
|
|
|
|
|
Ah, but this sub-thread was a digression down the avenue of your question:
BillWoodruff wrote: If an IEnumerable "knew" its count ... is that a contradiction in terms?
BillWoodruff wrote: equating of an instance of List<T> with IEnumerable<T>
Logically, every List<T> is an IEnumerable<T> , but not all IEnumerable<T> are List<T> .
"These people looked deep within my soul and assigned me a number based on the order in which I joined."
- Homer
|
|
|
|
|
Hi, Yes, i should welcome digressions coming up in soil i've freshly plowed
Richard Deeming wrote: Logically, every List<T> is an IEnumerable<T>, but not all IEnumerable<T> are List<T> Semantically, i respectfully disagree with that statement: imho, all generic Lists implement enumerability; but, an IEnumerable is a very special type of object that a generic list is not equatable to.
The list is a baby, alive and kicking; the IEnumerable is a fetus waiting to be born
«The mind is not a vessel to be filled but a fire to be kindled» Plutarch
|
|
|
|
|
BillWoodruff wrote: an IEnumerable is a very special type of object that a generic list is not equatable to
Since you can't create an instance of an interface, there isn't really an "IEnumerable object". There are only objects which implement IEnumerable.
"These people looked deep within my soul and assigned me a number based on the order in which I joined."
- Homer
|
|
|
|
|
We may not end up eye=>to<=eye on this one ... of course, on a practical level, we both use IEnumerable with skill (for most of us it takes some time to achieve a sense of mastery).
Let me ask you to imagine you are teaching a bright young person how to use Linq: they ask you, one day: "what is an IEnumerable before it gets iterated ?" ... what metaphor, or analogy, would you use to communicate your understanding ?
I run a Linq operator on a collection that returns an IEnumerable<T> : I get a result which is a ""System.Linq.Enumerable+WhereListIterator`1[[System.Int32, System.Private.CoreLib" ... I call that an instance of a special object, a kind of "alternate reality" with some unique methods ('MoveNext, etc. and facilities (deferred execution.
List<int> ints0 = new List<int>() { 1, 2, 3, 4, 5, 6, 7, 8 };
var ienm = ints0.Where(itm => itm > 2); I examine the Type:
> ? ienm.GetType()
{Name = "WhereListIterator`1" FullName = "System.Linq.Enumerable+WhereListIterator`1[[System.Int32, System.Private.CoreLib, Version=5.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e]]"}
Assembly: {System.Linq, Version=5.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a}
AssemblyQualifiedName: "System.Linq.Enumerable+WhereListIterator`1[[System.Int32, System.Private.CoreLib, Version=5.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e]], System.Linq, Version=5.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"
Attributes: NestedPrivate | Sealed | BeforeFieldInit
BaseType: {Name = "Iterator`1" FullName = "System.Linq.Enumerable+Iterator`1[[System.Int32, System.Private.CoreLib, Version=5.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e]]"}
«The mind is not a vessel to be filled but a fire to be kindled» Plutarch
modified 20-Jan-22 10:33am.
|
|
|
|
|
BillWoodruff wrote: Clearly, some collections "know" their count, because it is a Property not a method.. But, a generic IEnumerable created at run-time ? Right, so for most things, TryGetNonEnumeratedCount just returns false. It doesn't give the count in general, it gives the count in special cases such as when the IEnumerable<T> is actually a List<T> or something similar that has a known count, that's the point. BTW you can check the source.
BillWoodruff wrote: fascinating; I try to imagine a case of a generic IEnumerable where Count() would be more efficient ... but, draw a blank There's little chance of that, it's about the special cases again, you can see someone elses benchmarks here. They are cases in which Any and Count are both pretty fast (no significant iteration happens), but not equally fast and Count won. Those results are probably not valid anymore for .NET 6, in which Any has similar shortcuts as Count and TryGetNonEnumeratedCount have, but it made sense back in the days of .NET 4.8 and such, back then Count already had the shortcuts (TryGetNonEnumeratedCount didn't exist yet) but Any didn't have shortcuts so it wasted time creating an enumerator and calling MoveNext on it even for collections with a known count.
About 3 & 4, it depends. Depending on where those IEnumerables come from, that might perform a database query twice or call a function with a side-effect extra times (the IEnumerable could have different contents the next time, including changing its length). The safe thing to do is ToList -ing the IEnumerable at this point.. but that's the opposite of what you were trying to do. The predicate passed into a (for example) Where should be a pure function (then multiple evaluations are safe, just cost time) but C# has no mechanism to enforce that.
Sticking with Where for now, aside from literally changing the result, there is also potentially a lot of time wasted (depending on where the source IEnumerable comes from, how expensive the Where predicate is, and how often the predicate is true) by first finding the first element that passes the predicate (for Any ), and then doing it again when the IEnumerable is used "for real". It's avoidable but a little messy. Duplicate work is easier to avoid in the case that Any returns false.
TBH I'm leaning more and more in favour of avoiding this whole mess, but IDK what kind of algorithm you're dealing with..
|
|
|
|
|
Thanks ! Really appreciate the details on the behavior of count/any in .NET history.
The timing study you cited is very interesting, but, my concern here is with IEnumerables that have not yet been iterated over.
i have seen an example of a generic class that inherits from IEnumerable<t>, overrides 'MoveNext, and sets a boolean property initialized to 'false to 'true, the first time 'MoveNext is called. i regret to say i can't find that code now ... which is driving me nuts.
If i understood what i have read recently, 'Any() will call 'MoveNext at least once, but, on return the Enumerable's 'current property will be #0. Interesting the source for 'Any shows it tries to convert the input to an IList: if that succeeds, it returns the IList .Count property.
i should make the context more specific here:
1) at runtime you have a collection, say: a List<int>
2. function chaining: you run that List through a series of Func methods each of which returns an IEnumerable<int>. assume you have good reasons for writing separate Funcs
2a) one case is cumulative: you collect the outcome of each Func, and concatenate that with some external IEnumerable variable you've defined/initialized. in this case a no-values result may not make a difference since such a rsult dioes not throw an error if concatenated.
2b) another case: you are filtering the source data, selecting the next items from the results of calling the previous Func. A series of "sieves" if you will.
3) consider the case where you want to do something when any of the series of Func calls returns an IEnumerable with no elements ... assume you have a method/Action defined that can be invoked by any of the series of Funcs in this "no result" case.
4) now consider the final IEnumerable result of the series of Funcs, assuming they were all invoked, and returned some values.
a) the benefits of using 'Any after each Func call seem obvious ... but ...
b) in the context of iterating the final IEnumerable result:
1) would converting the result of each Func call to a List or Array, have any benefits ?
or, any downside ?
«The mind is not a vessel to be filled but a fire to be kindled» Plutarch
|
|
|
|
|
BillWoodruff wrote: My impression in the SO thread cited is that this new Linq method is somehow more efficient.
Based on my experience I would not trust linq to be efficient at all. Made worse by people not even understanding what it might do.
The most major case is when linq is used with database queries. Via profiling I have seen numerous cases where the linq code that would seem to translate into a single SQL query that would return a very limited set instead pulls major parts of the table or even the entire table into memory and then processes via C# to get the results.
The second case is where a programmer is handed a dictionary and then uses linq to search for a key in the dictionary. But the form that they use means that linq will iterate all of the keys and look for a match rather than using the key directly. Not saying there isn't a different way to use it but rather I have seen it programmed this way so often that I have started to look for it.
|
|
|
|
|
Thanks ! I appreciate hearing you observations.
Re Dictionary: since Keys are implemented as Hashes, does this affect search by Linq ?
The canonical way to search for a (possibly not present) Key in a Dictionary is via 'TryGetValue: tale a look at the internal implementation of 'FindVal which 'TryGetValue uses.
Dictionary iteration: [^]
«The mind is not a vessel to be filled but a fire to be kindled» Plutarch
|
|
|
|
|
BillWoodruff wrote: Re Dictionary: since Keys are implemented as Hashes, does this affect search by Linq ?
Idea of a Dictionary/hash is that it first uses the hash to find a bucket then uses the bucket (list) to find an exact match. Within the constraints of the data, especially larger sets, using that algorithm can be much more efficient than just searching a list sequentially. With all things using is correctly for the case is important.
Dictionaries can also iterate on all of the contents. So you use it just like a list. And in the cases I have seen people have been doing that.
BillWoodruff wrote: The canonical way to search for a (possibly not present) Key in a Dictionary is via
The programmers just want to find it by key but use linq which instead resolves to a list lookup. And in that case it is a programmer fault not linq.
|
|
|
|
|
Hello,
Can we remove a page from a pdf document using C#? I started to look at the
PrintDocument object part of the
System.Drawing.Printing; namespace. In a bit of crunch time, please let me know if this is possible before we take this option of the table.
thanks a bunch!
|
|
|
|
|
PrintDocument doesn't do anything with or to PDF files - it has no idea they even exist!
All it is concerned with is letting you format and convert your data to a format that the selected printer understands - no more than that.
If you actually want to remove a page from a PDF file, you will have to access and modify the file itself, which you do by reading the PDF file, and only importing the pages you want - then exporting the data to a (preferably new) file.
You can do that with iTextSharp, I believe, but I've not tried it myself: c# - itextsharp trimming pdf document's pages - Stack Overflow[^]
"I have no idea what I did, but I'm taking full credit for it." - ThisOldTony
"Common sense is so rare these days, it should be classified as a super power" - Random T-shirt
AntiTwitter: @DalekDave is now a follower!
|
|
|
|
|
Thank you so much for clarifying. Really appreciate the timely response!
|
|
|
|
|
You're welcome!
"I have no idea what I did, but I'm taking full credit for it." - ThisOldTony
"Common sense is so rare these days, it should be classified as a super power" - Random T-shirt
AntiTwitter: @DalekDave is now a follower!
|
|
|
|
|
using System;
using System.IO;
using System.Globalization;
namespace NamespaceName
{
public class ClassName
{
const int maxiter = 1000;
const double eps = 1e-12;
public static double hypot(double a,double b)
{
double absa,absb;
absa = Math.Abs(a);
absb = Math.Abs(b);
if(absa > absb) return absa * Math.Sqrt(1+(double)(absb/absa)*(double)(absb/absa));
else return (absb == 0?0: absb * Math.Sqrt(1 + (double)(absa/absb)*(double)(absa/absb)));
}
public static void printMatrix(int m,int n, double[,] A)
{
NumberFormatInfo nfi = new NumberFormatInfo();
nfi.NumberDecimalDigits = 12;
for(int i = 0;i < m;i++)
{
for(int j = 0; j < n; j++)
{
Console.Write("{0} , ",A[i,j].ToString("N",nfi));
}
Console.WriteLine();
}
Console.WriteLine();
}
public static void QR_Givens(int m,int n,double [,] A,double[,] Q)
{
for(int i = 0; i < m; i++)
for(int j = 0; j < m; j++)
Q[i,j] = (i == j ? 1 : 0);
int min = (m < n ? m : n);
for(int i = 0; i < min; i++)
{
for(int j = i + 1; j < m; j++)
{
if(A[j,i] != 0)
{
double r = hypot(A[i,i],A[j,i]);
double c = (double) (A[i,i]/r);
double s = (double) (A[j,i]/r);
for(int k = 0;k < n; k++)
{
double temp = A[i,k];
A[i,k] = c * A[i,k] + s * A[j,k];
A[j,k] = -s * temp + c * A[j,k];
}
for(int k = 0;k < m;k++)
{
double temp = Q[k,i];
Q[k,i] = c * Q[k,i] + s * Q[k,j];
Q[k,j] = -s * temp + c * Q[k,j];
}
}
}
}
}
public static void copyMatrix(double[,] A,double[,] B,int m,int n)
{
for(int i = 0;i < m;i++)
for(int j = 0;j < n;j++)
B[i,j] = A[i,j];
}
public static void multiplyMatrix(double[,] A,double[,] B,double[,] C,int m,int n,int p)
{
for(int i = 0;i < m;i++)
for(int j = 0;j < p;j++)
{
double sum = 0;
for(int k = 0;k < n;k++)
sum += A[i,k] * B[k,j];
C[i,j] = sum;
}
}
public static double rayleigh(int n, double[,] A,double[] q)
{
double norm = 0;
double sum;
double[] v = new double[n];
for(int i = 0;i < n;i++)
norm += q[i] * q[i];
for(int i = 0;i < n;i++)
{
sum = 0;
for(int j = 0;j < n;j++)
sum += A[i,j]*q[j];
v[i] = sum;
}
double r = 0;
for(int i = 0;i < n;i++)
r += q[i]*v[i];
r /= (double)norm;
return r;
}
public static void Main(string[] args)
{
char esc;
int n;
double[,] A,Q,R;
double[] v;
double[] a;
double r;
Random rnd = new Random();
NumberFormatInfo nfi = new NumberFormatInfo();
nfi.NumberDecimalDigits = 12;
using(StreamWriter sw = new StreamWriter("polyroots.txt",true))
{
do
{
Console.WriteLine("Podaj stopien wielomianu");
int.TryParse(Console.ReadLine(),out n);
A = new double[n,n];
Q = new double[n,n];
R = new double[n,n];
v = new double[n];
a = new double[n + 1];
for(int i = n;i >= 0;i--)
{
Console.Write("Podaj a[{0}]= ", i);
double.TryParse(Console.ReadLine(),out a[i]);
}
for(int i = n;i >= 0;i--)
if(a[i] < 0)
sw.WriteLine("-{0}x^{1} ",(-a[i]).ToString("N",nfi),i);
else
sw.WriteLine("+{0}x^{1} ",a[i].ToString("N",nfi),i);
sw.WriteLine();
for(int i=0;i<n;i++)
A[0,i] = (double)(-a[n-i-1]/a[n]);
for(int i = 1;i < n;i++)
for(int j = 0;j<n;j++)
A[i,j] = (i == j+1)?1:0;
printMatrix(n,n,A);
for(int i = 0;i < n;i++)
{
for(int j = 0; j < n; j++)
sw.Write("{0} ",A[i,j].ToString("N",nfi));
sw.WriteLine();
}
sw.WriteLine();
for(int i = 0;i < n;i++)
v[i] = i + rnd.NextDouble();
for(int i = 0;i < maxiter;i++)
{
r = rayleigh(n,A,v);
for(int j = 0;j < n;j++)
A[j,j] -= r;
QR_Givens(n,n,A,Q);
copyMatrix(A,R,n,n);
multiplyMatrix(R,Q,A,n,n,n);
for(int j = 0;j < n;j++)
A[j,j] += r;
for(int j = 0;j < n;j++)
v[j] = Q[n-1,j];
}
printMatrix(n,n,A);
for(int i = 0;i < n;i++)
{
for(int j = 0; j < n; j++)
sw.Write("{0} ",A[i,j].ToString("N",nfi));
sw.WriteLine();
}
sw.WriteLine();
Console.WriteLine("Pierwiastki danego rownania wielomianowego to: ");
sw.WriteLine("Pierwiastki danego rownania wielomianowego to: ");
int k = 0;
while(k<n)
{
if(k + 1 < n && Math.Abs(A[k+1,k])>eps)
{
double p = 0.5*(A[k,k]+A[k+1,k+1]);
double q = A[k,k] * A[k+1,k+1] - A[k,k+1] * A[k + 1,k];
double d = q - p * p;
Console.WriteLine("x[{0}]={1}-{2}i",k,p.ToString("N",nfi),Math.Sqrt(d).ToString("N",nfi));
Console.WriteLine("x[{0}]={1}+{2}i",k+1,p.ToString("N",nfi),Math.Sqrt(d).ToString("N",nfi));
sw.WriteLine("x[{0}]={1}-{2}i",k,p.ToString("N",nfi),Math.Sqrt(d).ToString("N",nfi));
sw.WriteLine("x[{0}]={1}+{2}i",k+1,p.ToString("N",nfi),Math.Sqrt(d).ToString("N",nfi));
k += 2;
}
else
{
Console.WriteLine("x[{0}]={1}",k,A[k,k].ToString("N",nfi));
sw.WriteLine("x[{0}]={1}",k,A[k,k].ToString("N",nfi));
k++;
}
}
esc = (char) Console.ReadKey().Key;
}
while(esc != (char)ConsoleKey.Escape);
}
}
}
}
How can i improve this code
Is Rayleigh quotient shift calculated correctly
Maybe other shift would be better
What other improvements could be made
|
|
|
|
|
What is wrong for you with this presented code?
Doesn't it work properly?
Does it work tooooo long?
Why should it be improved?
|
|
|
|
|
It works but it could work more efficiently
For example is Rayleigh quotient calculated properly
or maybe i could use better shift and how to do it
Maybe better stop condition ?
Did you have numerical methods ?
Have you remember topics from this
|
|
|
|
|
You can improve the code by using real variable names, not A, B C.....
The difficult we do right away...
...the impossible takes slightly longer.
|
|
|
|
|
You are very wise did you know that ?
|
|
|
|
|
You asked.
The difficult we do right away...
...the impossible takes slightly longer.
|
|
|
|
|
Finding roots of a polynomial is an ill-conditioned problem. There are better ways of dealing with this problem than using matrices.
|
|
|
|
|