2

下午,

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

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

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

4

5 回答 5

2

我知道这个问题已经得到解答,但我不能拒绝你这个我曾经做过 的小扩展方法,从那以后它对我很有帮助。

你可以做:

foreach(var list in prodASINs.ToChunks(10))
{
    // send list
}
于 2012-07-21T21:00:51.783 回答
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
}
于 2012-07-18T13:23:40.050 回答
1

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

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

如果你能够做到这一点,那么你可以做类似的事情

SELECT asin FROM datasource WHERE addedASIN = 0 LIMIT 10;

然后,一旦 MWS 返回成功添加,使用更新标志

UPDATE datasource SET addedASIN = 1 WHERE asin = 'asinnumber';

我发现这样做的好处是您的数据库将能够停止并以最少的数据重复开始 - 例如在我的情况下(以及启动此控制列的原因)我们的网络连接可能不稳定,所以我在订单导入我会失去连接,导致订单丢失,或者订单被上传到我们的系统两次。

由于连接丢失,该解决方案最多可以添加 1 个订单,并且为了将该订单上传两次,在将数据发送到我们的 ERP 系统、我们的 ERP 系统之间需要丢失连接确认已添加并更新数据库,往返大约需要 30 秒。

于 2012-07-18T13:32:19.890 回答
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);
}
于 2012-07-18T13:34:16.670 回答
-1

List<T>有一个名为的内置函数GetRange(),它是专门为你想要做的事情而制作的。它非常快,不需要 Linq、casting 等......

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
}

而已。很简单。


测试结果:GetRangevs. Slicevs. Linqwith 5000 stringsList<string> 可以清楚地看到,使用 Linq 的 Skip/Take 方法比 383 倍Slice<T>()和 4736 倍GetRange()

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

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);

}
于 2012-07-22T13:50:48.177 回答