How can you compare an INT to many other INTs? - c#

Well,
int a = 20;
int b = 30;
int c = 40;
int d = 50;
if (a > b,c,d)
how would i approach this, i have no idea i fail at every turn, its been hours

If there is a short quantity of numbers, you can simply use the boolean logic:
if (a > b && a > c && a > d)
{
}
If you don't know in advance the quantity of numbers, what about creating a collection and compare the first number to the numbers from the collection through a loop?
var numbers = { 30, 40, 50 };
if (!numbers.Any(c => 20 <= c))
{
}

You can put them in an array:
int a = 20;
int[] others = { 30, 40, 50 };
if(others.All(o => a > o))
{
// do something
}

Put them all in a list and do this:
if(list.All(x=> a > x))
Or in one line:
if(new List<int>{a, b, c, d}.All(x=> a > x))
EDIT
I changed the Max() to All(x => a > x) because the a > x will not return a true when a == x whereas Max() will do that.

Non-LINQ example:
if (Math.Max(a, Math.Max(b, Math.Max(c, d))) == a)
{
}

If all you want to know is if the number x is greater than the other numbers, you could either compare them explicitly like if(x>b & b>c) or use something like if(list.All(x=> a > x))
as mentioned above. If you have many numbers and all you want is the higher number, you could sort the list using a quick sort that could be efficient and get the first item.
It's a bit different if you need to compare them and get different comparissons then probably the easiest thing is to loop through the list.

Related

Group dateTime by hour range

I got a list like this:
class Article
{
...
Public DateTime PubTime{get;set}
...
}
List<Article> articles
Now I want to group this list with hour range :[0-5,6-11,12-17,18-23]
I know there is a cumbersome way to do this:
var firstRange = articles.Count(a => a.PubTime.Hour >= 0 && a.PubTime.Hour <= 5);
But I want to use a elegant way. How can I do that?Use Linq Or anything others?
Group by Hour / 6:
var grouped = articles.GroupBy(a => a.PubTime.Hour / 6);
IDictionary<int, int> CountsByHourGrouping = grouped.ToDictionary(g => g.Key, g => g.Count());
The key in the dictionary is the period (0 representing 0-5, 1 representing 6-11, 2 representing 12-17, and 3 representing 18-23). The value is the count of articles in that period.
Note that your dictionary will only contain values where those times existed in the source data, so it won't always contain 4 items.
You could write a CheckRange Function, which takes your values and returns a bool. To make your code more reusable and elegant.
Function Example:
bool CheckRange (this int number, int min, int max)
=> return (number >= min && number <= max);
You could now use this function to check if the PubTime.Hour is in the correct timelimit.
Implementation Example:
var firstRange = articles.Count(a => a.CheckRange(0, 5));

Code not returning expected number of even and odds

I have a function that takes in a list of numbers and will return how many even numbers and odd numbers there are in the list. However, I passed in a list of numbers but I'm getting 0 results.
Here is my function -
public static string HowManyEvenAndOdds(List<int> numbers)
{
int numOfOdds = 0;
int numOfEvens = 0;
int numOfBoth = 0;
foreach (int i in numbers) {
bool isEven = i % 2 == 0;
bool isOdd = i % 3 == 0;
numOfBoth = isEven && isOdd ? numOfBoth++ : numOfBoth;
numOfEvens = isEven ? numOfEvens++ : numOfEvens;
numOfOdds = isOdd ? numOfOdds++ : numOfOdds;
}
return string.Format("This list has {0} odd numbers,\n{1} even numbers,\nand {2} numbers that are even and odd.", numOfOdds, numOfEvens, numOfBoth);
}
Any ideas on what I'm doing wrong here? I debugged through it but none of the lists are incrementing.
Thanks
your are not calculating odd in the correct way
i%3 does not catch 5 which is also an odd number, try this instead
bool isEven = i % 2 == 0;
bool isOdd =!isEven;
I agree with Schachaf Gortler's answer as well as p.s.w.g's comment. Just do:
foreach (var number in numbers)
{
// A number is even if, and only if, it's evenly divisible by 2
if (number % 2 == 0)
numEvens++;
// A number is odd if, and only if, it's NOT evenly divisible by 2
// Alternatively, a number is odd if it isn't even and vice versa
else
numOdds++;
}
As p.s.w.g. mentioned, there's no such thing as a number that's both even and odd, so eliminate that completely.
Incidentally, numOfEvens++ retrieves the value and then increments it, which is why your code didn't work.
I think you should have a look at your test for isOdd
Use the Linq Count extension.
int numOfOdds = numbers.Count(x => x % 2 != 0);
int numOfEvens = numbers.Count(x => x % 2 == 0);
Of course you don't need to evaluate both expressions, as per the comment below.

C# Linq, find lowest value in List<int> between two numbers

I know this question has been asked before, but the other questions are only about finding the CLOSEST. I dont want that. I need the LOWEST between two values. For example if this is the list:
Code from How to get the closest number from a List<int> with LINQ?:
List<int> numbers = new List<int>();
numbers.Add(2);
numbers.Add(5);
numbers.Add(7);
numbers.Add(10)
and the number to find is 9, I want it to return the 7 item, not 10 even though its closer. This code finds the closest, but any time I change it to find the lowest in the range it breaks for other situations where the inputted number is one of the numbers in the list(for example 7 or 10):
list.Aggregate((x,y) => Math.Abs(x-number) < Math.Abs(y-number) ? x : y);
How do I alter that code to support what I need to do?
I know I could use binarysearch... I don't want to use that, I want to use linq if possible.
var numbers = new List<int> { 2, 5, 7, 10 };
var seven = numbers.Where(n => n <= 9).Max();
If you have to consider cases where the list will not any number closest, the code would look like,
private static int? GetClosest(List<int> numbers, int number)
{
var shorterEnumerable = numbers.Where(x => x <= number);
var shorterArray = shorterEnumerable as int[] ?? shorterEnumerable.ToArray();
if (shorterArray.Length > 1)
return shorterArray.Max();
return null;
}
even #danielnixon answer is good, this uses agregate
int? closerLow = (int?) list.Aggregate((x,y) => Math.Abs(x-number) < Math.Abs(y-number)
? (x > number ? y : x )
: (y > number ? x : y));
if (closerLow > number) closerLow = null;

Clean way to reduce many TimeSpans into fewer, average TimeSpans?

I have a C# Queue<TimeSpan> containing 500 elements.
I need to reduce those into 50 elements by taking groups of 10 TimeSpans and selecting their average.
Is there a clean way to do this? I'm thinking LINQ will help, but I can't figure out a clean way. Any ideas?
I would use the Chunk function and a loop.
foreach(var set in source.ToList().Chunk(10)){
target.Enqueue(TimeSpan.FromMilliseconds(
set.Average(t => t.TotalMilliseconds)));
}
Chunk is part of my standard helper library.
http://clrextensions.codeplex.com/
Source for Chunk
Take a look at the .Skip() and .Take() extension methods to partition your queue into sets. You can then use .Average(t => t.Ticks) to get the new TimeSpan that represents the average. Just jam each of those 50 averages into a new Queue and you are good to go.
Queue<TimeSpan> allTimeSpans = GetQueueOfTimeSpans();
Queue<TimeSpan> averages = New Queue<TimeSpan>(50);
int partitionSize = 10;
for (int i = 0; i <50; i++) {
var avg = allTimeSpans.Skip(i * partitionSize).Take(partitionSize).Average(t => t.Ticks)
averages.Enqueue(new TimeSpan(avg));
}
I'm a VB.NET guy, so there may be some syntax that isn't 100% write in that example. Let me know and I'll fix it!
Probably nothing beats a good old procedural execution in a method call in this case. It's not fancy, but it's easy, and it can be maintained by Jr. level devs.
public static Queue<TimeSpan> CompressTimeSpan(Queue<TimeSpan> original, int interval)
{
Queue<TimeSpan> newQueue = new Queue<TimeSpan>();
if (original.Count == 0) return newQueue;
int current = 0;
TimeSpan runningTotal = TimeSpan.Zero;
TimeSpan currentTimeSpan = original.Dequeue();
while (original.Count > 0 && current < interval)
{
runningTotal += currentTimeSpan;
if (++current >= interval)
{
newQueue.Enqueue(TimeSpan.FromTicks(runningTotal.Ticks / interval));
runningTotal = TimeSpan.Zero;
current = 0;
}
currentTimeSpan = original.Dequeue();
}
if (current > 0)
newQueue.Enqueue(TimeSpan.FromTicks(runningTotal.Ticks / current));
return newQueue;
}
You could just use
static public TimeSpan[] Reduce(TimeSpan[] spans, int blockLength)
{
TimeSpan[] avgSpan = new TimeSpan[original.Count / blockLength];
int currentIndex = 0;
for (int outputIndex = 0;
outputIndex < avgSpan.Length;
outputIndex++)
{
long totalTicks = 0;
for (int sampleIndex = 0; sampleIndex < blockLength; sampleIndex++)
{
totalTicks += spans[currentIndex].Ticks;
currentIndex++;
}
avgSpan[outputIndex] =
TimeSpan.FromTicks(totalTicks / blockLength);
}
return avgSpan;
}
It's a little more verbose (it doesn't use LINQ), but it's pretty easy to see what it's doing... (you can a Queue to/from an array pretty easily)
I'd use a loop, but just for fun:
IEnumerable<TimeSpan> AverageClumps(Queue<TimeSpan> lots, int clumpSize)
{
while (lots.Any())
{
var portion = Math.Min(clumpSize, lots.Count);
yield return Enumerable.Range(1, portion).Aggregate(TimeSpan.Zero,
(t, x) => t.Add(lots.Dequeue()),
(t) => new TimeSpan(t.Ticks / portion));
}
}
}
That only examines each element once, so the performance is a lot better than the other LINQ offerings. Unfortunately, it mutates the queue, but maybe it's a feature and not a bug?
It does have the nice bonus of being an iterator, so it gives you the averages one at a time.
Zipping it together with the integers (0..n) and grouping by the sequence number div 10?
I'm not a linq user, but I believe it would look something like this:
for (n,item) from Enumerable.Range(0, queue.length).zip(queue) group by n/10
The take(10) solution is probably better.
How is the grouping going to be performed?
Assuming something very simple (take 10 at a time ), you can start with something like:
List<TimeSpan> input = Enumerable.Range(0, 500)
.Select(i => new TimeSpan(0, 0, i))
.ToList();
var res = input.Select((t, i) => new { time=t.Ticks, index=i })
.GroupBy(v => v.index / 10, v => v.time)
.Select(g => new TimeSpan((long)g.Average()));
int n = 0;
foreach (var t in res) {
Console.WriteLine("{0,3}: {1}", ++n, t);
}
Notes:
Overload of Select to get the index, then use this and integer division pick up groups of 10. Could use modulus to take every 10th element into one group, every 10th+1 into another, ...
The result of the grouping is a sequence of enumerations with a Key property. But just need those separate sequences here.
There is no Enumerable.Average overload for IEnumerable<TimeSpan> so use Ticks (a long).
EDIT: Take groups of 10 to fit better with question.
EDIT2: Now with tested code.

What is the simplest way to initialize an Array of N numbers following a simple pattern?

Let's say the first N integers divisible by 3 starting with 9.
I'm sure there is some one line solution using lambdas, I just don't know it that area of the language well enough yet.
Just to be different (and to avoid using a where statement) you could also do:
var numbers = Enumerable.Range(0, n).Select(i => i * 3 + 9);
Update This also has the benefit of not running out of numbers.
Using Linq:
int[] numbers =
Enumerable.Range(9,10000)
.Where(x => x % 3 == 0)
.Take(20)
.ToArray();
Also easily parallelizeable using PLinq if you need:
int[] numbers =
Enumerable.Range(9,10000)
.AsParallel() //added this line
.Where(x => x % 3 == 0)
.Take(20)
.ToArray();
const int __N = 100;
const int __start = 9;
const int __divisibleBy = 3;
var array = Enumerable.Range(__start, __N * __divisibleBy).Where(x => x % __divisibleBy == 0).Take(__N).ToArray();
int n = 10; // Take first 10 that meet criteria
int[] ia = Enumerable
.Range(0,999)
.Where(a => a % 3 == 0 && a.ToString()[0] == '9')
.Take(n)
.ToArray();
I want to see how this solution stacks up to the above Linq solutions. The trick here is modifying the predicate using the fact that the set of (q % m) starting from s is (s + (s % m) + m*n) (where n represent's the nth value in the set). In our case s=q.
The only problem with this solution is that it has the side effect of making your implementation depend on the specific pattern you choose (and not all patterns have a suitable predicate). But it has the advantage of:
Always running in exactly n iterations
Never failing like the above proposed solutions (wrt to the limited Range).
Besides, no matter what pattern you choose, you will always need to modify the predicate, so you might as well make it mathematically efficient:
static int[] givemeN(int n)
{
const int baseVal = 9;
const int modVal = 3;
int i = 0;
return Array.ConvertAll<int, int>(
new int[n],
new Converter<int, int>(
x => baseVal + (baseVal % modVal) +
((i++) * modVal)
));
}
edit: I just want to illustrate how you could use this method with a delegate to improve code re-use:
static int[] givemeN(int n, Func<int, int> func)
{
int i = 0;
return Array.ConvertAll<int, int>(new int[n], new Converter<int, int>(a => func(i++)));
}
You can use it with givemeN(5, i => 9 + 3 * i). Again note that I modified the predicate, but you can do this with most simple patterns too.
I can't say this is any good, I'm not a C# expert and I just whacked it out, but I think it's probably a canonical example of the use of yield.
internal IEnumerable Answer(N)
{
int n=0;
int i=9;
while (true)
{
if (i % 3 == 0)
{
n++;
yield return i;
}
if (n>=N) return;
i++;
}
}
You have to iterate through 0 or 1 to N and add them by hand. Or, you could just create your function f(int n), and in that function, you cache the results inside session or a global hashtable or dictionary.
Pseudocode, where ht is a global Hashtable or Dictionary (strongly recommend the later, because it is strongly typed.
public int f(int n)
{
if(ht[n].containsValue)
return ht[n];
else
{
//do calculation
ht[n] = result;
return result;
}
}
Just a side note. If you do this type of functional programming all the time, you might want to check out F#, or maybe even Iron Ruby or Python.

Categories