如何删除中间的重复项

时间:2016-08-16 20:00:54

标签: linq enumerable

给出如下序列: -

var list = new[] {"1a", "1b", "1c", "1d", "2a", "3a", "4a", "4b", "5a", "6a", "7a", "7b", "8a"}.Select(x => new { P1 = x.Substring(0,1), P2 = x.Substring(1,1)});

我想删除"中间"中的重复项。最终: -

var expected = new[] {"1a", "1d", "2a", "3a", "4a", "4b", "5a", "6a", "7a", "7b", "8a"}.Select(x => new { P1 = x.Substring(0, 1), P2 = x.Substring(1, 1) });

因此,任何超过两次的重复都会被删除。尽管我获得了第一个和最后一个复制品,这一点非常重要。

2 个答案:

答案 0 :(得分:1)

对于那些没有聚合并想要使用闭包的超短答案的人:

var data = new[] { "1a", "1b", "1c", "1d", "2a", "3a", "4a", "4b", "1e", "5a", "6a", "7a", "7b", "8a" };
char priorKey = ' ';
int currentIndex = 0;

var result2 = data.GroupBy((x) => x[0] == priorKey ? new { k = x[0], g = currentIndex } : new { k = priorKey = x[0], g = ++currentIndex })
    .Select(i => new[] { i.First(), i.Last() }.Distinct())
    .SelectMany(i => i).ToArray();

给@Slai提供基于的代码的提示(我为非连续组问题添加了一个修复程序。)

以下是使用Aggregate的方法。 我没有测试所有边缘情况......只是你的测试用例。

var list = new[] { "1a", "1b", "1c", "1d", "2a", "3a", "4a", "4b", "5a", "6a", "7a", "7b", "8a" }
           .Aggregate(new { result = new List<string>(), first = "", last = "" },
              (store, given) =>
              {
                var result = store.result;
                var first = store.first;
                var last = store.last;

                 if (first == "")
                  // this is the first one.
                  first = given;
                else
                {
                  if (first[0] == given[0])
                    last = given;
                  else
                  {
                    result.Add(first);
                    if (last != "")
                      result.Add(last);
                    first = given;
                    last = "";
                  }

                }
                 return new { result = result, first = first, last = last }; },
                 (store) => { store.result.Add(store.first); if (store.last != "") store.result.Add(store.last); return store.result; })
           .Select(x => new { P1 = x.Substring(0,1), P2 = x.Substring(1,1)});

到目前为止,我创建了一个对象来保存列表,以及到目前为止已知的第一个和最后一个。

然后我只使用逻辑来移除中间的东西。

答案 1 :(得分:1)

按第一个字符分组,并取每组的第一个和最后一个项目:

var list = "1a 1b 1c 1d 2a 3a 4a 4b 5a 6a 7a 7b 8a".Split();

var result = list.GroupBy(i => i[0])
    .Select(i => new[] { i.First(), i.Last() }.Distinct())
    .SelectMany(i => i).ToArray();

Debug.Print(string.Join("\", \"", result)); 
// { "1a", "1b", "1c", "1d", "2a", "3a", "4a", "4b", "5a", "6a", "7a", "7b", "8a" }