Sunny
Sunny

Reputation: 3295

How I can do this using skip and take in linq

I have a dataset which contains more than 50k rows. I decided to take average of the first fifty values, then second fifty values and so on (so that I will get half of the Dataset with average of 50 value groups).

Here is my code:

var Rate = (from dr in ds.Tables[0].AsEnumerable()
                                    select new
                                    {
                                        rate = dr.Field<double>(columnName)
                                    }.rate).ToList();
                            if (Rate.Count > 50)
                            {
                                var avg = Rate.CheckRateValue();
                            }

And here is the code for my extension method:

public static IEnumerable<double> CheckRateValue(this IEnumerable<double> values)
{
    int i = 1;
    int j = 0;
    for (; i < values.Count(); )
    {
        yield return values.Skip(j * 2).Take(2).Average();
        i = i + 2;
        j++;
    }
}

Problem : It works fine but it's slow. Does anyone have any suggestions on how to speed it up?

Upvotes: 0

Views: 246

Answers (6)

Sunny
Sunny

Reputation: 3295

By using row_number() i solved it.

declare @Skip int = 20
declare @Take int = 10

select SomeColumn
from (
   select SomeColumn,
          row_number() over(order by SomeColumnToOrderBy) as rn
   from YourTable
 ) T
where rn > @Skip and 
  rn <= @Skip + @Take

Upvotes: 0

Amy B
Amy B

Reputation: 110121

for { yield return values.Skip(j * 2).Take(2).Average(); }

Moving to the current page from the start in each loop iteration: that will be n^2. See also Schlemiel the painter.

You should enumerate values once!

Upvotes: 0

Tilak
Tilak

Reputation: 30708

If you want to take items in count of fifty and average it (like take first 50 , average it, take next 50, average it, and so on), and get list of Averages, you can use MoreLinq.Batch

You can use

  var result = list.Batch(50).Select(x=> x.Average());

Upvotes: 1

shf301
shf301

Reputation: 31394

Using the DataTable.Compute may be faster because you skip the iteration to create List<dobule>.

double average = (double)ds.Tables[0].Compute("avg(columnName)", "");

The second parameter is a fitler expression so you could use it to do your skipping if the data in the table allows it.

Upvotes: 2

Dave Bish
Dave Bish

Reputation: 19646

Why would that be any faster than simply:

var average = dat.AsEnumerable().Average(dr => (double)dr["ColumnName"]);

In fact - this should probably be faster than the extra complexity of taking 50 at a time...

Upvotes: 0

Massimiliano Peluso
Massimiliano Peluso

Reputation: 26737

var yourList=yourList.Take(50).Aggregate((acc, cur) => acc + cur) / list.Count

Upvotes: 1

Related Questions