Max value from list that is smaller than X - c#

How to retrieve int value from List that is biggest number on it but still smaller than X value to which i am comparing.
Value = 10
Example one: List = {1,4,6,8}; => number 8 biggest on list and smaller than 10
Example two: List = {1,15,17,20}; => number 1 biggest on list and smaller than 10
I was trying using Linq but no success so far.

You can just restrict the values you use to get the "Max" by using a Where clause:
return myList.Where(x => x < 10).Max();

You can use Where to filter your values which less than 10 and use Max to get maximum values in them like;
var list = new List<int>{1, 15, 17, 20};
list.Where(s => s < 10).Max().Dump();

you can filter items less than x and then find the max by using Max() as below
list.where(m => m <= x).Max(p => p);

Related

MVC 5 How to bind linq result(Number) to array[i]?

Let's say i have a inventory slot range from 1 to 100 how to find the first empty slot from the range?
First, i'm thinking of using Array.FindIndex but i'm stuck at here.
var InventorySlot = (from i in db.InventoryModel where i.userId == 1 select i.slot).ToArray();
int index = Array.FindIndex(InventorySlot, item => item == null );
But this will create
InventorySlot[0] = 1
InventorySlot[1] = 3
InventorySlot[2] = 4
So how to create like this?
InventorySlot[1] = x
InventorySlot[3] = x
InventorySlot[4] = x
Perhaps i can use Array.FindIndex to locate the empty array? The index variable i need is 2(First empty number in the array)
What you need to do is compare the result from the database with the range without exceptions:
var firstEmptySlot = Enumerable.Range(1, InventorySlot.Max()).Except(InventorySlot).First();
If you want to get the largest slot plus one if no slot is empty, you can do:
var firstEmptySlot = Enumerable.Range(1, InventorySlot.Max()+1).Except(InventorySlot).First();
You would need to test firstEmptySlot in this case to make sure it is <= 100.
You could combine testing and the query by limiting the range to 1 - 100:
var firstEmptySlot = Enumerable.Range(1, Math.Min(InventorySlot.Max()+1, 100)).Except(InventorySlot).FirstOrDefault();
You will get a 0 back if no empty slots from 1 - 100 are available.

C# resulting sequence using Where clause

I was doing some work by my own for upcoming test and found this question that I could not understand.
int[] div = new int[]{2,3,5};
IEnumerable<int>seq = new int[]{10,15,20,25,30};
for(int i = 0; i<div.Length;i++){
int y = div[i];
seq = seq.Where(s => s%y == 0)
}
seq = seq.ToList();
I thought the resulting sequence would be 10 15 20 25 30 but the actual answer was 30.
I tried to run the code by my self and I found that when the code runs the for-loop, the sequence does not resets to the original but it keeps the sequence created by the previous div[i].
For example, when i = 0, div[0] is 2 so the seq picks the 10, 20 and 30.
As the code proceeds to i = 1 and div[1] = 3, the sequence it uses for the calculation part is still {10,20,30} not {10,15,20,25,30}.
Can someone explain why?
When I move int y to the outside of the for-loop like this,
int[] div = new int[]{2,3,5};
IEnumerable<int>seq = new int[]{10,15,20,25,30};
int y;
for(int i = 0; i<div.Length;i++){
y = div[i];
seq = seq.Where(s => s%y == 0)
}
seq = seq.ToList();
it gives the answer I was expecting.
Any help will be really helpful.
Thank you.
This is the resulting query you end up with:
IEnumerable<int> seq = new int[]{10,15,20,25,30};
seq = seq
.Where(s => s%2 == 0)
.Where(s => s%3 == 0)
.Where(s => s%5 == 0);
So, every number that is divisible by 2, 3 and 5:
10 is not divisible by 3
15 is not divisible by 2
20 is not divisible by 3
25 is not divisible by 2
30 is divisible by 2 (15), 3 (10), and 5 (6)
So 30 is the only result.
Now, if you instead want this query: "I want every number in seq that is divisible by 2, 3 or 5", then you need to do it different.
The code you had will filter every step of the way, only letting through to the next step any numbers that fit, so each will filter, but you want the opposite, if any one of them would say that it was OK, then you want the number.
To get the or expression instead, this would be the code:
seq.Where(s => div.Any(y => s % y == 0))
This gives this result:
10
15
20
25
30
Basically this query says:
Any number s in seq, which for any number y in div, where s is divisible by y.
As for your last part, why did it change after you moved the y outside the loop?
Well, let's see what actually happens.
When you have the y inside the loop, as in the first example, for each iteration through the loop, you can think of y as a "new y just for this loop iteration".
As such, you can think of the code that is being executed producing this query:
int y1 = 2;
int y2 = 3;
int y3 = 5;
seq = seq
.Where(s => s%y1 == 0)
.Where(s => s%y2 == 0)
.Where(s => s%y3 == 0);
But, if you move the y variable outside the loop you only ever have one y, which you change, so the final result is this:
int y = 5; // the last number in the loop
seq = seq
.Where(s => s%y == 0)
.Where(s => s%y == 0)
.Where(s => s%y == 0);
Which basically checks that every number is divisible by 5, 3 times.
So while you say that this gives you the result you want, it doesn't do what you want. Or rather, I assume it doesn't do what you want since you haven't actually described what you wanted the code to do.
Here are some links that explain the differences:
Anonymous Methods (MSDN)
Captured variable in a loop in C#
Detailed Explanation of Variable Capture in Closures
You code can be simplified by adding some more LINQness.
If what you are trying to get is the values of seq that can be divided by any of the values of div, you can simply do:
seq.Where(s => div.Any(d => s%d == 0));
If you want the values of seq that can be divided by all of the values of div, replace the .Any with .All.

Find First Unique Number

I recently took a Codility test and the question was to find the first unique number in a numeric sequence. Although I get the correct result using LINQ, it is apparently too expensive computationally and not scalable enough.
How would I improve my solution?
var a = new int[] {1, 2, -3, 4, 5, -6, 0, 8, 9, 1, 2};
const int expected = -3;
var retVal = -1;
var y = a.GroupBy(z => z).Where(z => z.Count() == 1).Select(z => z.Key).ToList();
if (y.Count > 0) retVal = y[0];
Console.Write(retVal==expected);
How about this:
var result = a.ToLookup(i => i).First(i => i.Count() == 1).Key;
This should give -3.
It builds a Lookup object with a key created using each number in the list, and a value of the same number.
In the case of duplicates, then multiple entries are created under each key. The first unique value will be the first group in the Lookup with one entry.
(You could just as easily use GroupBy, instead of ToLookup. The end result will be the same.)
try this
var result = a.GroupBy(g => g).Where(w => w.Count() == 1).Select(s => s.Key).FirstOrDefault();
I decided to test the various answers posted above and count the number of ticks using the StopWatch class.
Changing y.Count > 0 to y.Any() resulted in the second lowest tick count, but the largest reduction belongs to the group by comment from Baldrick
To get the average each test was run 50 times.
Ticks
Min Max Avg Actual
2 14502 584 -3 Original
2 919 40 -3 if (y.Any()) actual = y[0];
2 1423 60 -3 a.GroupBy(g => g).Where(w => w.Count() == 1)
.Select(s => s.Key)
.FirstOrDefault();
2 1553 65 -3 a.ToLookup(i => i).First(i => i.Count() == 1).Key;
2 317 15 -3 a.GroupBy(i => i).First(i => i.Count() == 1).Key;

Create intervals of data with LINQ

I have an issue in C# that I can't figure out how to solve:
I have a set of data that consist of a TimeStamp and a value.
This is a sample dataset:
<Timestamp>2014-01-06T17:40:08.000Z</TimeStamp>
<Value>200</Value>
<Timestamp>2014-01-06T17:40:09.000Z</TimeStamp>
<Value>234</Value>
<Timestamp>2014-01-06T17:40:11.000Z</TimeStamp>
<Value>214</Value>
<Timestamp>2014-01-06T17:40:12.000Z</TimeStamp>
<Value>264</Value>
<Timestamp>2014-01-06T17:40:13.000Z</TimeStamp>
<Value>300</Value>
<Timestamp>2014-01-06T17:40:15.000Z</TimeStamp>
<Value>276</Value>
What I need to do is to somehow get the average of the values by every 30 seconds. Notice that the recordings of data is not necessarily every second. This is what makes it hard for me to imagine how to do this without having an insecurity in the results.
Is this achievable through a LINQ statement or do you have other suggestions?
Assuming you can figure out how to parse the XML, and you have a collection of objects with Time and Value. For example, I'll use this collection:
var now = DateTime.Now;
var random = new Random();
var times = Enumerable.Range(1, 10000).Select(i => new
{
Time = now.AddHours(random .NextDouble()),
Value = i
});
Using a helper method DateTime RoundUp(DateTime dt, TimeSpan d), and GroupBy:
var interval = TimeSpan.FromSeconds(30);
var intervalAverageValues =
times.GroupBy(t => RoundUp(t.Time, interval))
.Select(g => new
{
AverageValue = g.Average(t => t.Value),
IntervalEndTime = g.Key,
Count = g.Count()
});
Consider this pseudo answer :)
Take your list of values and their timestamps and produce a list of Tuple<int, int>{} this is assuming your values are ints. Where first int is index and second int is the value;
As you are filling the tuples list you need to take the total seconds component of your timestamp and divide it by 30. The result should be rounded to closest int.
At this point you have a list of tuples that has values paired with their corresponding '30 second' group index;
Use a simple group linq to produce your averages. Basically you loop over your groups and sum the values. Then divide by group's item count;
This is brute force approach somewhat. I'm sure there are smarter ways to do this.

How to extract values from arrays using upper and lower limits?

Given two arrays, I need to extract values from arrayB based on where the range(actual values) falls in arrayA.
Index 0 1 2 3 4 5 6 7 8 9 10 11 12
-------------------------------------------------------------
ArrayA = {0, 0.5, 1, 1.5, 2, 2.5, 3, 3.5, 4, 4.5, 5, 5.5, 6}
ArrayB = {1, 0.2, 3, 4, 5, 6,5.5, 8, 9,11.1, 11, 12, 3}
Given the following ranges, I need to extract the following results
RangeToExtract* IndexInArrayA Expected Values To Extract
-------------- ------------- --------------------------
0 -> 1 [0,2] 1,0.2,3
1 -> 3 [3,6] 4,5,6,5.5
3 -> 5 [7,10] 5.5,8,9,11.1,11
1 -> 5 [3,10] 4,5,6,5.5,8,9,11.1,11
3 -> 10 [7,12] 8,9,11.1,11,12,3
* Refers to the actual values in ArrayA
Note: Given the RangeToExtract (0->1), determine the indexes in ArrayA where these values are, the result being (0->1) maps to [0,2] (The value 1 is in position 2 in ArrayA)
I only figured that the following special cases exists (not sure if there are more)
the lower limit is equal to zero and
when the upper limit does not exist in ArrayA
Further info:
Both arrays will be the same size
ArrayA will always be sorted
Code:
private double[] GetRange(double lower, double upper)
{
var myList = new double[ArrayA.Length];
var lowerIndex = Array.IndexOf(ArrayA, lower);
var upperIndex = Array.IndexOf(ArrayA, upper);
// special case 1
if (lowerIndex != 0)
{
lowerIndex = lowerIndex + 1;
}
// special case 2
if (upperIndex == -1)
{
upperIndex = ArrayA.Length-1;
}
for (int i = lowerIndex; i <= upperIndex; i++)
{
myList[i] = ArrayB[i];
}
return myList;
}
Given the above code, have all the special cases been taken into account? Is there a better way to write the above code?
Yap! There is a quite better way, that comes with lovely LINQ. I put here in two forms. First looks complicated but not at ALL! Believe me ;)
At the first step you have to take out those A'indexes that their values fall into your range (I call it min...max), based on your example I got that your range is closed from the lower boundary and closed on upper side, I means when you mentioned 3 -> 5 actually It is [3, 5)! It does not contain 5. Anyway that is not the matter.
This can be done by following LINQ
int[] selectedIndexes = a.Select((value, index) =>
new { Value = value, Index = index }).
Where(aToken => aToken.Value > min && aToken.Value <= max).
Select(t => t.Index).ToArray<int>();
The first select, generates a collection of [Value, Index] pairs that the first one is the array element and the second one is the index of the element within the array. I think this is the main trick for your question. So It provides you with this ability to work with the indexes same as usual values.
Finally in the second Select I just wrap whole indexes into an integer array. Hence after this you have the whole indexes that their value fall in the given range.
Now second step!
When you got those indexes, you have to select whole elements within the B under the selected Indexes from the A. The same thing should be done over the B. It means again we select B element into a collection of [Value, Index] pairs and then we select those guys that their indexes exist within the selected indexes from the A. This can be done as follow:
double[] selectedValues = b.Select((item, index) =>
new { Item = item, Index = index }).
Where(bToken => selectedIndexes.Contains(bToken.Index)).
Select(d => d.Item).ToArray<double>();
Ok, so first select is the one I talked about it in the fist part and then look at the where section that check whether the index of the bToken which is an element of B exists in the selectedIndexes (from A) or not!
Finally I wrap both codes into one as below:
double[] answers = b.Select((item, index) =>
new { Item = item, Index = index }).
Where(bTokent =>
a.Select((value, index) =>
new { Value = value, Index = index }).
Where(aToken => aToken.Value > min && aToken.Value <= max).
Select(t => t.Index).
Contains(bTokent.Index)).Select(d => d.Item).ToArray<double>();
Buy a beer for me, if it would be useful :)
I don't know if you're still interested, but I saw this one and I liked the challenge. If you use .Net 4 (having the Enumberable.Zip method) there is a very concise way to do this (given the conditions under futher info):
arrayA.Zip(arrayB, (a,b) => new {a,b})
.Where(x => x.a > lower && x.a < upper)
.Select (x => x.b)
You may want to use >= and <= to make the range comparisons inclusive.

Categories

Resources