Reputation: 520
I have a collection of type NumberList
.
public class NumberList
{
public int Number { get; set; }
public double Profit { get; set; }
public DateTime CloseTime { get; set; }
}
All records are stored in NumberList and sorted in descending order by Number and Date.
Now i need to loop through whole list searching for Number that have 10 entries and store them in new list.
Problem i have is that i am getting 10 values but not for same number, like number 26724 have 9 entries and he take next one 18450 and add it also in list because it missing 1. Instead of adding other number it need to reset tempList
and go on next number since it have only 9 entries.
How i can extract first 10 entries of same number and add them to new list ?
Here is code:
var tempList = new List<NumberList>(); // temporary list
var finalList = new List<NumberList>(); // new list where we store final results
foreach (var item in NumberList)
{
tempList.Add(item); // add numbers to temp list
// if temlist contains Number and number of items in list is less then 10
if (tempList.Contains(item) && tempList.Count() < 10)
{
finalList.Add(item);
}
else
{
if (tempList.Count() == 10) // check for number of items in list
{
tempList.Clear(); // reset tempList
}
}
}
Example how it need to work: Number 26724 have only 9 entries so he will not be in new list, number 18450 have 8 entries he will not be on list, number 16822 have 20 entries so we take first 10 entries of that number and put in new list.
26724, -6.55, 18-Jul-19 08:32:30
26724, 12.21, 20-Jun-19 03:54:56
26724, -6.53, 14-Jun-19 20:09:28
26724, 12.15, 31-May-19 17:13:25
26724, 0.98, 21-May-19 09:00:01
26724, 4.21, 15-May-19 07:02:02
26724, -6.56, 08-May-19 18:00:43
26724, -7.35, 24-Apr-19 18:40:25
26724, -6.59, 04-Apr-19 21:08:40
18450, 6.79, 18-Jul-19 22:16:26
18450, 6.69, 20-Jun-19 03:31:27
18450, 6.82, 14-Jun-19 09:57:16
18450, 6.66, 31-May-19 20:27:05
18450, -0.28, 13-May-19 15:59:08
18450, -5.95, 08-May-19 18:00:01
18450, -3.53, 24-Apr-19 12:00:42
18450, -6.05, 04-Apr-19 21:00:03
16822, 10.38, 11-Jul-19 04:56:27
16822, 9.88, 27-Jun-19 09:00:00
16822, 0.43, 17-Jun-19 16:00:02
16822, -2.36, 11-Jun-19 04:00:00
16822, -9.82, 05-Jun-19 20:08:02
16822, 13.31, 31-May-19 21:06:21
16822, 1.49, 22-May-19 10:00:02
16822, -2.8, 17-May-19 12:00:01
16822, -8.8, 13-May-19 15:07:46
16822, -8.43, 10-May-19 21:49:31
16822, -5.84, 03-May-19 16:45:26
16822, -4.91, 01-May-19 21:38:06
16822, -0.58, 01-May-19 06:00:03
16822, -1.43, 26-Apr-19 13:00:01
16822, -4.4, 25-Apr-19 10:11:29
16822, -3.58, 23-Apr-19 16:26:34
16822, -0.97, 18-Apr-19 00:01:36
16822, -2.8, 11-Apr-19 14:00:31
16822, 2.48, 05-Apr-19 13:00:15
16822, 0.2, 04-Apr-19 00:01:44
...... etc
So our new list should look like this from this example:
16822, 10.38, 11-Jul-19 04:56:27
16822, 9.88, 27-Jun-19 09:00:00
16822, 0.43, 17-Jun-19 16:00:02
16822, -2.36, 11-Jun-19 04:00:00
16822, -9.82, 05-Jun-19 20:08:02
16822, 13.31, 31-May-19 21:06:21
16822, 1.49, 22-May-19 10:00:02
16822, -2.8, 17-May-19 12:00:01
16822, -8.8, 13-May-19 15:07:46
16822, -8.43, 10-May-19 21:49:31
Upvotes: 1
Views: 1992
Reputation: 23732
Now i need to loop through whole list searching for Number that have 10 entries and store them in new list.
Foeach is not very well suited to do this job. You need 2 For-Loops. One for each (distinct)item number and one for the comparison. Since your collection is ordered you can use this to avoid multiple iterations over the base collection. Every time when a new series starts you can remember the index end the inner loop and jump in the outer loop to the remembered location:
for (int i = 0; i < NumberList.Count; i++)
{
tempList.Clear();
for (int j = i+1; j < NumberList.Count; j++)
{
if (NumberList[i].Number == NumberList[j].Number)
{
tempList.Add(NumberList[i]);
}
else
{
// Note that a new series of numbers has began and jump to this position
i = j;
break; // end this counting procedure
}
}
// at this point evalueate the counter
if (tempList.Count >= 10)
{
finalList.AddRange(tempList.Take(10));
}
}
As short Linq solution could look like this:
NumberList.GroupBy(x => x.Number).Where(x => x.Count() >= 10).SelectMany(x => x.Take(10));
Simply gather all numbers with the same value into grouped collections.
Then apply a filter on it to check which one fit your criterion being there 10 times or more.
Then select only those items/ungroup them and take only the first 10;
Upvotes: 3
Reputation: 71
You can make a distinct on the field Number and cycle the object with the result of the distinct
foreach (var item in numList.Select(x=> x.Number).Distinct())
{
int counter = 0;
if(numList.Where(x=> x.Number.Equals(item)).Count() >= 10 )
{
foreach( var item2 in numList.Where(x=> x.Number.Equals(item)) ){
if(counter <10 ) {
finalList.Add(item2);
counter ++;
}
}
}
}
foreach(var test in finalList)
Console.WriteLine(string.Format("{0}, {1}", test.Number, test.Profit));
Upvotes: 0
Reputation: 2072
var tempList = new List<NumberList>(); // temporary list
var finalList = tempList.GroupBy(t => t.Number)
.Where(t => t.Count() >= 10)
.SelectMany(t => t.Take(10)) //take 10 elements from filtered data
.ToList();
Upvotes: 0
Reputation: 5812
You can use Linq to do this. For example,
var finalList = numberList
.GroupBy(a => a.Number)
.Where(a => a.Count() >= 10)
.SelectMany(a => a.OrderBy(b => b.CloseTime).Take(10))
.ToList();
So firstly we group by the number using GroupBy
. Then, we restrict to only the groupings that contain 10 or more entries using Where(a => a.Count() >= 10)
. Then we use SelectMany
to flatten the groupings, and select the first 10 elements of each grouping using Take
, with an OrderBy
to make sure they're in a consistent order.
Upvotes: 3
Reputation: 15772
NumberList
.GroupBy(x => x.Number)
.Where(groupings => grouping.Count() > 10)
.SelectMany(groupings => groupings)
.ToList()
Upvotes: 1