ok, this should be interesting.
lets assume i have the following code:
in this example, the first available number would be 2.
List<long> myList = new List<long>(){0,1,10,3};
in this example, the first available number would be '4'.
List<long> myList = new List<long>(){0,1,2,3};
any ideas?
So by "available" you mean "the lowest non-negative number which doesn't already exist in the list"?
I'd be tempted to write something like:
HashSet<long> existing = new HashSet<long>(list);
for (long x = 0; x < long.MaxValue; x++)
{
if (!existing.Contains(x))
{
return x;
}
}
throw new InvalidOperationException("Somehow the list is enormous...");
EDIT: Alternatively, you could order the list and then find the first value where the index isn't the same as the value...
var ordered = list.OrderBy(x => x);
var differences = ordered.Select((value, index) => new { value, index })
.Where(pair => pair.value != pair.index)
.Select(pair => (int?) pair.index);
var firstDifference = differences.FirstOrDefault();
long nextAvailable = firstDifference ?? list.Count;
The last line is to take care of the situation where the list is contiguous from 0. Another alternative would be:
var nextAvailable = list.Concat(new[] { long.MaxValue })
.OrderBy(x => x)
.Select((value, index) => new { value, index })
.Where(pair => pair.value != pair.index)
.Select(pair => pair.index)
.First();
This should be fine so long as the list doesn't contain long.MaxValue + 1 elements, which it can't in current versions of .NET. (That's a lot of memory...) To be honest, this will already have problems when it goes beyond int.MaxValue elements due to the Select part taking an int index...
list.Sort();
var range = Enumerable.Range( list.First(), list.Last()- list.First());
var number = range.Except(list).FirstOrDefault();
Related
Here is what i have so far
int[] numbers = { 3,5,4,3,8,8,5,3,2,1,9,5 };
int[] n = new int[12];
int[] k;
foreach (int number in numbers)
{
n[number]++;
}
Array.Sort(n);
Array.Reverse(n);
foreach (int value in n)
{
Console.WriteLine(value);
}
I know i am missing the part where i sort the frequency of the elements after i counted them and i just cant get my head around it. I'd appreciate some help, Thanks!
What's the problem with your solution ?
Whereas you correctly keep the frequencies of the numbers in the table called n in your code, which hereby I would call it frequencies, then you Sort this array. This action breaks your solution, since each frequency is associated with the corresponding index of its location in the array.
E.g. If an instance of this array is this [8,2,1,7,6]. When you call the Sort method on this array, this would have as a result the array to be sorted and the order of the elements of the array would be this [1,2,7,6,8]. Before calling sort, the first element of the array was indicating that the number 0 (the index of the first element is 0) has been found 8 times in our numbers. After sort, the first element is 1, which means now that the frequency of the number 0 is 1, which is apparently wrong.
If you want to keep it your way, then you could try something like this:
int[] numbers = { 1,2,2,9,1,2,5,5,5,5,2 };
int[] frequencies = new int[12];
int k = 3;
foreach (int number in numbers)
{
frequencies[number]++;
}
var mostFrequentNumbers = frequencies.Select((frequency, index) => new
{
Number = index,
Frequency = frequency
})
.OrderByDescending(item => item.Frequency)
.Select(item => item.Number)
.Take(k);
foreach (int mostFrequentNumber in mostFrequentNumbers)
{
Console.WriteLine(mostFrequentNumber);
}
Are there any other approaches ?
An easy way to do this is to use a data structure like a Dictionary, in which you would keep as keys the numbers and as the corresponding values the corresponding frequencies.
Then you can order by descending values the above data structure an keep the k most frequent numbers.
int[] numbers = { 1,2,2,9,1,2,5,5,5,5,2 };
int k = 3;
Dictionary<int, int> numberFrequencies = new Dictionary<int, int>();
foreach (int number in numbers)
{
if(numberFrequencies.ContainsKey(number))
{
numberFrequencies[number] += 1;
}
else
{
numberFrequencies.Add(number, 1);
}
}
var mostFrequentNumbers = numberFrequencies.OrderByDescending(numberFrequency => numberFrequency.Value)
.Take(k)
.Select(numberFrequency => numberFrequency.Key);
foreach (int mostFrequentNumber in mostFrequentNumbers)
{
Console.WriteLine(mostFrequentNumber);
}
You can also achieve the same thing by only using LINQ:
int[] numbers = { 1,2,2,9,1,2,5,5,5,5,2 };
int k = 3;
var mostFrequentNumbers = numbers.GroupBy(number => number)
.ToDictionary(gr => gr.Key, gr => gr.Count())
.OrderByDescending(keyValue => keyValue.Value)
.Take(k)
.Select(numberFrequency => numberFrequency.Key);
foreach (int mostFrequentNumber in mostFrequentNumbers)
{
Console.WriteLine(mostFrequentNumber);
}
You can just use Linq extensions:
using System.Linq;
using System.Collections.Generic;
...
private static IEnumerable<int> Solve(int[] numbers, int k) {
return numbers
.GroupBy(x => x)
.OrderByDescending(g => g.Count())
.Select(g => g.Key)
.Take(k);
}
Then you can call:
var numbers = new []{1,2,2,9,1,2,5,5,5,5,2};
var k = 3;
var result = Solve(numbers, k);
foreach (int n in result)
Console.WriteLine(n);
To be very terse:
var frequents = numbers.GroupBy(t => t)
.Where(grp => grp.Count() > 1)
.Select(t => t.Key)
.OrderByDescending(t => t)
.Take(k)
.ToList();
I'm having some trouble doing it right.
I need to pick the minimum and maximum for a list inside a list inside a list
Any thought how I can create a optimized type?
var range = allFilteredCars
.SelectMany(car => car.LeasingPlans
.SelectMany(plan => plan.Durations)
.Select(a => a.MonthlyPrice))
.ToList();
var min = range.Min();
var max = range.Max();
The last Min() and Max() doesn't feel right.
Any thoughts?
I can think of only one way to calculate min and max just by iterating one time on the entire collection which can be done using foreach loop
var min = Int32.MaxValue;
var max = Int32.MinValue;
foreach(var filteredCard in allFilteredCars)
{
foreach(var leasingPlan in filteredCard.LeasingPlans)
{
foreach(var car in leasingPlan.Durations)
{
if(car.MonthlyPrice < min)
min = car.MonthlyPrice;
else if(car.MonthlyPrice > max)
max = car.MonthlyPrice;
}
}
}
Assuming MonthlyPrice is of Int
We will do a bad thing: a linq expression with a side effect.
int? min = null;
int? max = null;
allFilteredCars
.SelectMany(car => car.LeasingPlans
.SelectMany(plan => plan.Durations))
.Select(a =>
{
if (min == null || a.MonthlyPrice < min.Value)
{
min = a.MonthlyPrice;
}
if (max == null || a.MonthlyPrice > max.Value)
{
max = a.MonthlyPrice;
}
return true;
}).All(x => x);
In the end you don't really seem to need the range result... You only want the Min() and Max(), so we calculate it, and force the whole IEnumerable<> to be elaborated through the use of All().
You have to replace int? with the type of MonthlyPrice!
I don't think you can get around the multiple SelectManys but an Ordering in the query will get rid of the Min/Max. This should be quicker as you are then only sorting once:
var range = allFilteredCars
.SelectMany(car => car.LeasingPlans
.SelectMany(plan => plan.Durations)
.Select(a => a.MonthlyPrice))
.OrderBy(a => a))
.ToList();
var min = range[0]; // get the first
var max = range[range.Count-1]; // get the last
Assume that I have a list of items from 1 - 3.
I could order them by 1,1,2,2,3,3.
But instead, I would like to order them by 1,2,3,1,2,3....
Is there an already exist function to achieve that?
This approach separates each number into groups, then iterates through the groups in order while conditionally adding them to a result list. There's probably ways to make this safer and more efficient, but this should give you a start. (It assumes that if there aren't equal counts of each number in the source array, it will skip those numbers as it runs out of them during the iteration phase.)
int[] arr = new[] { 1,1,1,2,2,2,3,3,3,4,4,4,5,5,5 };
var orderList = arr.OrderBy(x => x).Distinct().ToArray();
var refList = arr.GroupBy(x => x).ToDictionary(k => k.Key, v => v.Count());
var result = new List<int>();
int i = 0;
while (result.Count < arr.Length)
{
if (refList.Values.Sum() == 0)
break;
if (refList[orderList[i]] > 0)
{
result.Add(orderList[i]);
refList[orderList[i]]--;
}
i++;
if (i >= orderList.Length)
i = 0;
}
// Result: [1,2,3,4,5,1,2,3,4,5,1,2,3,4,5]
I want to make a ranking from a list and output it on original order.
This is my code so far:
var data = new[] { 7.806468478, 7.806468478, 7.806468478, 7.173501754, 7.173501754, 7.173501754, 3.40877696, 3.40877696, 3.40877696,
4.097010736, 4.097010736, 4.097010736, 4.036494085, 4.036494085, 4.036494085, 38.94333318, 38.94333318, 38.94333318, 14.43588131, 14.43588131, 14.43588131 };
var rankings = data.OrderByDescending(x => x)
.GroupBy(x => x)
.SelectMany((g, i) =>
g.Select(e => new { Col1 = e, Rank = i + 1 }))
.ToList();
However, the result will be order it from descending:
What I want is to display by its original order.
e.g.: Rank = 3, Rank = 3, Rank = 3, Rank = 4, Rank = 4, Rank = 4, etc...
Thank You.
Using what you have, one method would be to keep track of the original order and sort a second time (ugly and potentially slow):
var rankings = data.Select((x, i) => new {Item = x, Index = i})
.OrderByDescending(x => x.Item)
.GroupBy(x => x.Item)
.SelectMany((g, i) =>
g.Select(e => new {
Index = e.Index,
Item = new { Col1 = e.Item, Rank = i + 1 }
}))
.OrderBy(x => x.Index)
.Select(x => x.Item)
.ToList();
I would instead suggest creating a dictionary with your rankings and joining this back with your list:
var rankings = data.Distinct()
.OrderByDescending(x => x)
.Select((g, i) => new { Key = g, Rank = i + 1 })
.ToDictionary(x => x.Key, x => x.Rank);
var output = data.Select(x => new { Col1 = x, Rank = rankings[x] })
.ToList();
As #AntonínLejsek kindly pointed out, replacing the above GroupBy call with Distinct() is the way to go.
Note doubles are not a precise type and thus are really not a good candidate for values in a lookup table, nor would I recommend using GroupBy/Distinct with a floating-point value as a key. Be mindful of your precision and consider using an appropriate string conversion. In light of this, you may want to define an epsilon value and forgo LINQ's GroupBy entirely, opting instead to encapsulate each data point into a (non-anonymous) reference type, then loop through a sorted list and assign ranks. For example (disclaimer: untested):
class DataPoint
{
decimal Value { get; set; }
int Rank { get; set; }
}
var dataPointsPreservingOrder = data.Select(x => new DataPoint {Value = x}).ToList();
var sortedDescending = dataPointsPreservingOrder.OrderByDescending(x => x.Value).ToList();
var epsilon = 1E-15; //use a value that makes sense here
int rank = 0;
double? currentValue = null;
foreach(var x in sortedDescending)
{
if(currentValue == null || Math.Abs(x.Value - currentValue.Value) > epsilon)
{
currentValue = x.Value;
++rank;
}
x.Rank = rank;
}
From review of the data you will need to iterate twice over the result set.
The first iteration will be to capture the rankings as.
var sorted = data
.OrderByDescending(x => x)
.GroupBy(x => x)
.Select((g, i) => new { Col1 = g.First(), Rank = i + 1 })
.ToList();
Now we have a ranking of highest to lowest with the correct rank value. Next we iterate the data again to find where the value exists in the overall ranks as:
var rankings = (from i in data
let rank = sorted.First(x => x.Col1 == i)
select new
{
Col1 = i,
Rank = rank.Rank
}).ToList();
This results in a ranked list in the original order of the data.
A bit shorter:
var L = data.Distinct().ToList(); // because SortedSet<T> doesn't have BinarySearch :[
L.Sort();
var rankings = Array.ConvertAll(data,
x => new { Col1 = x, Rank = L.Count - L.BinarySearch(x) });
I have this code similar to this post
List<MyObject> myList = new List<MyObject>(){new MyObject { Number1 = 1, Number2 = 2, Number3 = 3 },
new MyObject { Number1 = 1, Number2 = 2, Number3 = 3 }};
var listWithoutDuplicated = myList
.GroupBy(x => new { x.Number1, x.Number2, x.Number3 })
.Select(x => x.First());
int counter = 0;
foreach (var item in listWithoutDuplicated)
{
counter ++;
}
That code would return counter = 1, so it works fine, but why is it necessary .Select(x => x.First()); and not only .First(); at the end?
// This code would not remove duplicates.
var listWithoutDuplicated = myList
.GroupBy(x => new { x.Number1, x.Number2, x.Number3 })
.First();
Thanks a lot.
.First() returns the first group from a sequence of groups.
Select(group => group.First()) takes a sequences of groups and returns a new sequence representing the first item in each group.
Both are entirely valid things to do, and also extremely different. You can see this by simply printing out the results, or for that matter, just looking at the type of the result (this would be more visible in the code if you did not usevar).