2010-10-01 52 views
8

我有一个列表:计数的重复号码列表

int list = { 1,1,2,3,4,4,5,7,7,7,10}; 

现在我需要做一个程序,计算出双号。当它之前的数字相同时,数字是双倍的。我希望你明白。所以1是双倍,4是双打,我们在7,7,7中得到2双。

+1

你可以提供更多的信息,为什么/如何?感觉像一个家庭作业/面试问题。如果找到匹配,只需使用一个循环来解决并比较之前的当前和存储/重置将是非常简单的 - 只是一些额外的逻辑来停止7被计数3次。如果你想用linq或其他东西来解决它,那就更有趣了。 – 2010-10-01 13:06:31

回答

26

下面是LINQ的溶液:

var doubles = list.Skip(1) 
        .Where((number, index) => list[index] == number); 

这通过跳过列表的第一个成员创建另一序列,然后发现从具有相同索引和相同的值两个序列元件。它将以线性时间运行,但只是因为列表按索引提供了O(1)访问权限。

+2

绝对+1。答案很简洁,正确(没有经过测试,但我承担风险),非常聪明,并且正确地论证了为什么它以线性时间运行。 – Fede 2010-10-01 13:17:45

+2

+1:非常优雅! – RedFilter 2010-10-01 13:18:56

+9

想象一下,把它作为家庭作业的答案复制,然后必须向班级(和老师)解释...... mwahahaha – 2010-10-01 13:47:49

2

这样的事情可能工作:

list.GroupBy (l => l).Where (l => l.Count() > 1).SelectMany (l => l).Distinct(); 

编辑:

上面的代码中并没有得到结果的OP通缉。下面是经编辑的版本,在下面,其灵感来自安仁的优雅的解决方案::)

list.GroupBy(l => l).Select(g=>g.Skip(1)).SelectMany (l => l); 
7

这里有一个方法是比较简单,只迭代一次在序列,并与任何序列作品(不只是列出):

public IEnumerable<T> FindConsecutiveDuplicates<T>(this IEnumerable<T> source) 
{ 
    using (var iterator = source.GetEnumerator()) 
    { 
     if (!iterator.MoveNext()) 
     { 
      yield break; 
     } 
     T current = iterator.Current; 
     while (iterator.MoveNext()) 
     { 
      if (EqualityComparer<T>.Default.Equals(current, iterator.Current)) 
      { 
       yield return current; 
      } 
      current = iterator.Current; 
     } 
    } 
} 

这里是另外一个是即使在它只是一个LINQ查询简单,但它使用Where子句,这是讨厌的副作用:

IEnumerable<int> sequence = ...; 

bool first = true; 
int current = 0; 
var result = sequence.Where(x => { 
    bool result = !first && x == current; 
    current = x; 
    first = false; 
    return result; 
}); 

第三种选择,这是有点清洁,但使用SelectConsecutive方法基本上是从SelectPairsthis answer,但改名为稍微清晰的:)

IEnumerable<int> sequence = ...; 
IEnumerable<int> result = sequence.SelectConsecutive((x, y) => new { x, y }) 
            .Where(z => z.x == z.y); 
+2

你是什么意思“使用副作用”? – 2010-10-01 13:11:45

+2

我的眼睛在流血。 – 2010-10-01 13:16:21

+0

@Lasse:好点。呃,我改变了我的计划。等一下,我会把副作用的版本备份:) – 2010-10-01 13:16:38

6

每个人似乎都试图找到这样做的好方法,所以这是一个非常糟糕的方式,而不是:

List<int> doubles = new List<int>(); 
Dictionary<int, bool> seenBefore = new Dictionary<int, bool>(); 

foreach(int i in list) 
{ 
    try 
    { 
     seenBefore.Add(i, true); 
    } 
    catch (ArgumentException) 
    { 
     doubles.Add(i); 
    } 
} 

return doubles; 

请不要这样做。

+0

哈哈,幽默感+1。这是星期五毕竟 – 2010-10-01 13:24:44

+0

谢谢。我不确定是否因为发布错误答案而得票低,或者因为发表不合格而赞成票。 :-) – teedyay 2010-10-01 13:38:32

+0

+1除了异常之外,它并不是一个完全不好的非Linq答案 - 你可以使用ContainsKey或TryGetValue来避免异常,它会很好。 – 2010-10-01 13:50:28

0

在这里,你的答案去在C#:)

int[] intarray = new int[] { 1, 1, 2, 3, 4, 4, 5, 7, 7, 7, 10 }; 

int previousnumber = -1; 
List<int> doubleDigits = new List<int>(); 
for (int i = 0; i < intarray.Length; i++) 
{ 
    if (previousnumber == -1) { previousnumber = intarray[i]; continue; } 
    if (intarray[i] == previousnumber) 
    { 
     if (!doubleDigits.Contains(intarray[i])) 
     { 
      doubleDigits.Add(intarray[i]); 
      //Console.WriteLine("Duplicate int found - " + intarray[i]); 
      continue; 
     } 
    } 
    else 
    { 
     previousnumber = intarray[i]; 
    } 
} 
0

是(可能)的性能比使用LINQ更好,虽然一个例子可以说是那么优雅:

for (int i = 1; i < list.Count; i++) 
    if (list[i] == list[i - 1]) 
     doubles.Add(list[i]); 
0

你可以这样做:

list.GroupBy(i => i).Where(g => g.Count() > 1).SelectMany(g => g.Skip(1)) 

这有点像@ KJN的回答,除了我认为它表达了“双打”和“双打”条款在这个问题好一点:

  1. 组的所有整数一起
  2. 只在那些出现不止一次兴趣(g.Count() > 1
  3. 选择“双打”的平面化列表,是与第一后(g.Skip(1)

PS:我们这里假设,即GroupBy不先排序列表,如果是的话,那那种没有负面的预排序列表的影响...