如何列表<t>?

时间:2017-05-06 14:01:50

标签: c# arrays list split microsoft-translator

我正在使用Microsoft Translator API,特别是TranslateArray方法。我的挑战是texts参数的内置限制:

[...]包含翻译文本的数组。 [...]所有要翻译的文本总数不得超过10000个字符。数组元素的最大数量为2000。

我得到一个可变长度的List元素 - 每个元素都有不同的长度(标题,描述)。我想将此数据传递给TranslateArray(),但它需要具有适当的大小。我怎么能这样做?

    public class TranslateItem
    {
        public string Title { get; set; }
        public string Desc { get; set; }
    }

    private static void chunkNorris()
    {
        // list contains elements to be translated
        var list = new List<TranslateItem>();

        var chunkList = new List<TranslateItem>();
        int itemLength = 0; int totalLength = 0;

        foreach (var batch in list.Batch(1000))
        {
            foreach (var item in batch)
            {
                itemLength = item.Title.Length + item.Desc.Length;
                totalLength = totalLength + itemLength;

                if (itemLength <= 10000 && totalLength <= 10000)
                {
                    chunkList.Add(new TranslateItem() { Title = item.Title, Desc = item.Desc });
                }
                else
                {
                    // do translation here...
                    // bug here: itemLength can be > 10000

                    // reset chunkList and add item to empty list
                    chunkList.Clear();
                    itemLength = totalLength = item.Title.Length + item.Desc.Length;
                    chunkList.Add(new TranslateItem() { Title = item.Title, Desc = item.Desc});
                }

                if (item.Equals(list.Last()))
                {
                    // do translation here...
                }
            }
        }
    }

更新:这就是我所拥有的。代码将以1000“批次”(即2列的1000个元素)运行并拆分数组,以符合2000数组元素限制。但是,它不能解决大小超过10,000个字符的问题。此外,代码非常笨拙 - 想知道是否可以使用LINQ以更优雅的方式完成。 Batch method from here

1 个答案:

答案 0 :(得分:1)

实际上,您应该修改Batch方法以获得两个分块规则而不是一个。也就是说,让我们从头开始吧。这里的基本技巧是利用C#内置的IEnumerable/yield支持。

您的目标是批量翻译项目。

public class TranslateItem
{
    public string Title { get; set; }
    public string Desc { get; set; }
}

所以,让我们从签名开始吧。给定一些要翻译的项目(IEnumerable<TranslateItem>),返回一些要翻译的分块项目(IEnumerable<IEnumerable<TranslateItem>>

private static IEnumerable<IEnumerable<TranslateItem>> 
    chunkNorris(IEnumerable<TranslateItem> data)
{

保持正在运行的一批项目进行翻译,跟踪该批次中字符的总长度:

    var chunkList = new List<TranslateItem>();
    int totalLength = 0;

逐个处理每个项目

    foreach (var item in data)
    {

计算批次中当前项目的长度:

        int itemLength = item.Title.Length + item.Desc.Length;

如果该项目有10000个字符,请以某种方式处理:

        if (itemLength > 10000)
        {
            throw new NotImplementedException("TODO");
        }

将该项目添加到当前批次是安全的,如果这样做不会违反我们的两条规则(不超过1000项/ 2000字符串且不超过10000个字符)。

        bool SafeToAddMoreData = 
            (itemLength+totalLength) <= 10000 && chunkList.Count < 1000;

如果扩展我们当前的块是不安全的,只需产生当前块,然后再创建一个新块。

        if(!SafeToAddMoreData)
        {
            yield return chunkList;
            chunkList = new List<TranslateItem>();
            totalLength = 0;
        }

现在可以安全地向我们当前的块添加更多数据,因为SafeToAddMoreData是假的,或者因为我们刚刚清除了当前的块。因此,向我们当前的块添加更多数据,确保更新块长度的运行总计。

        totalLength = totalLength + itemLength;
        chunkList.Add(item);

对每个块重复此过程

    }

我们的循环只在数据被阻止扩展当前块时才会吐出数据。吐掉最后一块。

    if (chunkList.Any()) //Always be true (unless data was empty).
    {
        yield return chunkList;
    }

该功能已完成。

}