如何将字符串列表拆分为较小的字符串列表块

时间:2018-08-13 14:53:07

标签: c# string list linq loops

我要解决的问题如下:

我有一个$version=Online "#% impex.setTargetFile( ""Product.csv"" );" insert_update Product ; catalog(id [allownull=true] ; catalogVersion(catalog(id),version)[unique=true,allownull=true] ; code[unique=true,allownull=true] ; name "#% impex.exportItems(""SELECT {P:pk} FROM {Product as P}, {CatalogVersion as CV}, {Catalog as C} WHERE {P:catalogversion}={CV:PK} AND {CV:catalog}={C:PK} AND {C:id}='$catalog' AND {CV:version}='$version'"", Collections.EMPTY_MAP, Collections.singletonList( Item.class ), true, true, -1, -1 );" ,我们称之为“ List<string>”。

我需要与该列表中的所有字符串进行交互,因此我必须对其进行枚举。但是,问题来了,每次我互动时,我都必须取其中的“ x”个元素。

initialListx,因此每次都是随机的。

这是我想要做的一个真实的例子:

假设列表new Random().Next(_minValue, _maxValue);包含以下元素: initialList

我想遍历所有元素,一次获取2-3个字符串,并用组合的元素保存一个新字符串。

因此,一种可能的输出(随随机返回的值而异)是:

test, test2, test3, test4, test5, test6, test7, test8, test9, test10, test11, test12

我想做什么:

{ "test",  "test1", "test2" }, 
{ "test3", "test4" }, 
{ "test5", "test6" }, 
{ "test7", "test8" }, 
{ "test9", "test10", "test11" }, 
{ "test12" }

我一直在思考,但是如果我在循环之外生成随机数,那么它将始终是相同的。我希望每次的字符串数量都是随机的。

此外,想到通过选择带有索引的元素来进行LINQ,但是不知道如何从那里继续。

感谢您的帮助。

6 个答案:

答案 0 :(得分:3)

希望这会给您一个想法。

var mergedList = new List<string>();
for(int i = 0; i < initialList.Count; ){
    var n = _random.Next(2,4);
    mergedList.Add(initialList.Skip(i).Take(n).Aggregate((x,y) => x + y));
    i += n;
}

答案 1 :(得分:2)

我认为最好的解决方案是使用LINQ Skip跳过您已经处理过的元素,并使用Take提取随机数量的元素。

const int _minValue = 2;
const int _maxValue = 4; // note max of random is exclusive, so this config takes 2 or 3 elements

var _random = new Random(Guid.NewGuid().GetHashCode());

List<string> initialList = new List<string>{"test", "test2", "test3", "test4", "test5", "test6", "test7", "test8", "test9", "test10", "test11", "test12"};

var currentPosition = 0;

while (currentPosition < initialList.Count()) {
    var toTake = _random.Next(_minValue, _maxValue);
    var mergedString = string.Join(", ", initialList.Skip(currentPosition).Take(toTake)); 
    currentPosition += toTake;
}

请注意,此代码可能导致最后一个mergedString仅包含一个元素(最后一个)。

工作示例:C# Fiddle

答案 2 :(得分:2)

您可以尝试直接GroupBy

  List<string> initialList = Enumerable
    .Range(1, 15)
    .Select(i => $"test{i}")
    .ToList();

  int _minMentions = 2;
  int _maxMentions = 3;

  // Random(1): to make outcome reproducible
  // In real life should be new Random();  
  Random _random = new Random(1); 

  int group = 0;
  int groupLength = 0;

  var result = initialList
    .Select((item) => {
      if (--groupLength <= 0) {
        group += 1;
        groupLength = _random.Next(_minMentions, _maxMentions + 1);
      }

      return new { item, group };
    })
    .GroupBy(item => item.group)
    .Select(chunk => chunk
       .Select(item => item.item)
       .ToList())
    .ToList();

  string test = string.Join(Environment.NewLine, result
    .Select(items => string.Join(", ", items))); 

  Console.Write(test);

结果:

test1, test2
test3, test4
test5, test6
test7, test8, test9
test10, test11, test12
test13, test14
test15

答案 3 :(得分:1)

您可以使用IEnumerable.Skip和Take循环遍历初始列表,并创建所需大小的块,直到需要处理的元素为止。

List<string> initiallist = new List<string>
{"test", "test2", "test3", "test4", "test5", "test6", "test7", "test8", "test9", "test10", "test11", "test12"};

// We store the results here    
List<List<string>> result = new List<List<string>>();

Random rnd = new Random();
int pos = 0;
while (pos < initiallist.Count())
{
    // Define a block size of 2/3 elements
    int block = rnd.Next(2,4);

    // Extract the block size from the previous position
    List<string> temp = initiallist.Skip(pos).Take(block).ToList();

    // Add the sublist to our results
    result.Add(temp);

    // Point to the beginning of the next block
    pos += block;

}

答案 4 :(得分:1)

使用Linq可以实现以下目的:

var initialList = new[]
{
    "test", "test2", "test3", "test4", "test5", "test6", "test7", "test8", "test9", "test10", "test11",
    "test12"
};

var newLists = new List<IEnumerable<string>>();
var rnd = new Random();
int minMentions = 2;
int maxMentions = 3;
int c = 0;

while (c < initialList.Length)
{
    int elementsToTake = rnd.Next(minMentions, maxMentions + 1);
    newLists.Add(initialList.Skip(c).Take(elementsToTake));
    c += elementsToTake;
}

(随机)导致的结果:

{ test, test2, test3 }
{ test4, test5 }
{ test6, test7, test8 }
{ test9, test10, test11 }
{ test12 }

请注意,Take仅接受可用物品,因此您不必担心elementsToTake的体积要大于initialList的体积。

答案 5 :(得分:0)

我知道有很多不错的答案,但是如果您喜欢IEnumerable,就可以尝试一下

public static class EnumerableGroupOf
    {
        public static IEnumerable<IEnumerable<TSource>> RandomGroupOf<TSource>(this IEnumerable<TSource> source, int[] groupLengths)
        {
            Random random = new Random();

            var itemsLeft = source;

            while (itemsLeft.Any())
            {
                var count = groupLengths[random.Next(0, groupLengths.Length)];

                var items = itemsLeft.Take(count);

                itemsLeft = itemsLeft.Skip(count);

                yield return items;
            }
        }
    }

这不会跳过而只处理铰孔的所有项目,因此使用Enumerable可能会更好。