将DB的结果拆分为10的“块”

时间:2012-07-18 13:20:37

标签: asp.net linq amazon-mws

下午,

我需要一手将1200多个结果分成10个“块”,这样我就可以使用亚马逊MWS API处理这些结果。任何人都可以就如何做到这一点提供任何指导吗?

 List<string> prodASIN = dc.aboProducts.Select(a => a.asin).Take(10).ToList();

我目前有这个,有效。但我有1200多个结果,需要遍历每个10,所以我可以处理它们并将它们传递给亚马逊MWS API

5 个答案:

答案 0 :(得分:2)

我知道这个问题得到了回答,但我不能拒绝你this little extension method我曾经做过的事情,从那以后我就一直很好。

你可以这样做:

foreach(var list in prodASINs.ToChunks(10))
{
    // send list
}

答案 1 :(得分:1)

为什么不尝试这样的事情:

//Load all the database entries into Memory
List<string> prodASINs = dc.aboProducts.Select(a => a.asin).ToList();
var count = prodASINs.Count();
//Loop through passing 10 at a time to AWS
for (var i = 0; i < count; i++)
{
    var prodASINToSend = prodASINs.Skip(i * 10).Take(10).ToList(); 
    //Send to AWS
}

或者如果您不想将它们全部加载到内存中。

var count = dc.aboProducts.Count();
for (var i = 0; i < count; i++)
{
    List<string> prodASIN = dc.aboProducts.OrderBy(a => a.Id).Select(a => a.asin).Skip(i * 10).Take(10).ToList(); 
    //Send to AWS
}

答案 2 :(得分:1)

对不起,这不是LINQ特定的,但也许它会有所帮助......

使用MWS和ERP软件处理数据时,我所做的一件事就是在数据库中添加一个控制列,类似于“addedASIN”。在数据库中,我将控制列定义为布尔值(或TINYINT( 1)在MySQL中)并将所有新条目的标志默认为0,并在添加条目时将其设置为1。

如果你能够做到这一点,那么你可以做一些像

这样的事情
SELECT asin FROM datasource WHERE addedASIN = 0 LIMIT 10;

然后,一旦MWS返回成功添加,使用

更新标志
UPDATE datasource SET addedASIN = 1 WHERE asin = 'asinnumber';

我发现这样做的好处是你的数据库能够停止并以最小的重复数据开始 - 例如在我的情况下(以及启动此控制列的内容)我们的网络连接可能是片状的,所以我在订单导入期间发现我会失去连接,导致订单丢失或订单上传到我们的系统两次。

此解决方案已经减轻了由于连接丢失导致最多添加两个订单,并且为了将该订单上传两次,在将数据发送到我们的ERP系统之间需要丢失连接,我们的ERP系统承认它已被添加并且数据库正在更新,这对于往返大约需要30秒。

答案 3 :(得分:0)

切片扩展(用于阵列):

    public static T[] Slice<T>(this T[] source, int index, int length)
    {
        T[] slice = new T[length];
        Array.Copy(source, index, slice, 0, length);
        return slice;
    }

Array.Copy非常快,比Select / Skip / Take模式快很多。虽然这种方法并不是我所发现的禁食方法,但最近的测试结果显示它比用于分割列表和数组的Skip / Take模式快近400倍。

按原样使用:

const int arraySize = 10;
List<string> listSource = whatever;
string[] source = listSource.ToArray();

for (int i = 0; i < source.Length; i += arraySize)
{
    List<string> buffer = source.Slice(i, arraySize).ToList();
    DoSomething(buffer);
}

答案 4 :(得分:-1)

List<T>有一个名为GetRange()的内置函数,专门针对您要执行的操作而制作。它非常快,不需要Linq,铸造等......

List<string> prodASINs = dc.aboProducts.Select(a => a.asin).ToList(); 

for(int i = 0; i < prodASINs.Count; i += 10)
{

    List<string> buffer = prodASINs.GetRange(i, 10);
    // do something with buffer
}

就是这样。非常简单。


测试结果:GetRangeSliceLinq的对比List<string>中有5000个字符串 您可以清楚地看到,使用Linq的Skip / Take方法比Slice<T>()慢383倍,比GetRange()慢4,736倍

=============================================== ===================================

GetRange took on average 168 ticks
Slice took on average 2073 ticks
Linq took on average 795643 ticks

使用的测试方法(自己尝试):

private static void GetRangeVsSliceVsLinq()
{
    List<string> stringList = new List<string>();
    for (int i = 0; i < 5000; i++)
    {
        stringList.Add("This is a test string " + i.ToString());
    }

    Stopwatch sw = new Stopwatch();

    long m1 = 0, m2 = 0, m3 = 0;


    for (int x = 0; x < 10; x++)
    {
        Console.WriteLine("Iteration {0}", x + 1);
        Console.WriteLine();

        sw.Reset();
        sw.Start();

        for (int i = 0; i < stringList.Count; i += 10)
        {
            List<string> buffer = stringList.GetRange(i, 10);
        }
        sw.Stop();
        Console.WriteLine("GetRange took {0} msecs", sw.ElapsedMilliseconds);
        Console.WriteLine("GetRange took {0} ticks", sw.ElapsedTicks);
        m1 += sw.ElapsedTicks;

        sw.Reset();
        sw.Start();

        string[] sliceArray = stringList.ToArray();
        for (int i = 0; i < sliceArray.Length; i += 10)
        {
            List<string> buffer = sliceArray.Slice(i, 10).ToList();
        }
        sw.Stop();
        Console.WriteLine("Slice took {0} msecs", sw.ElapsedMilliseconds);
        Console.WriteLine("Slice took {0} ticks", sw.ElapsedTicks);
        m2 += sw.ElapsedTicks;

        sw.Reset();
        sw.Start();

        var count = stringList.Count();
        for (var i = 0; i < count; i++)
        {
            var buffer = stringList.Skip(i * 10).Take(10).ToList();
        }

        sw.Stop();
        Console.WriteLine("Skip/Take took {0} msecs", sw.ElapsedMilliseconds);
        Console.WriteLine("Skip/Take took {0} ticks", sw.ElapsedTicks);
        m3 += sw.ElapsedTicks;

        Console.WriteLine();
    }

    Console.WriteLine();
    Console.WriteLine("GetRange took on average {0} ticks", m1 / 10);
    Console.WriteLine("Slice took on average {0} ticks", m2 / 10);
    Console.WriteLine("Linq took on average {0} ticks", m3 / 10);

}