リストに同じアイテムが3つあるかどうかを確認する必要があります。
オーバーライドされた.Equals()
メソッドを使用して要素を比較する必要があります。私は多くの方法を試しましたが失敗しました。ブール値を返すか、アイテム自体を返すかは関係ありません。この関数は、新しいアイテムが追加されるたびに呼び出されるため、同じアイテムが3つリストされているポイントを検出する限り、この関数は問題になりません。
これはおそらく些細なことですが、Linqに関する私の知識は非常に弱いです。
To express better my concept:
static class EnumerableExtensions
{
public static IEnumerable<T> FirstRepeatedTimes<T>(this IEnumerable<T> sequence, int threshold)
{
if (!sequence.Any())
throw new ArgumentException("Sequence must contain elements", "sequence");
if (threshold < 2)
throw new ArgumentException("DuplicateCount must be greater than 1", "threshold");
return FirstRepeatedTimesImpl(sequence, threshold);
}
static IEnumerable<T> FirstRepeatedTimesImpl<T>(this IEnumerable<T> sequence, int threshold)
{
var map = new Dictionary<T, int>();
foreach(var e in sequence)
{
if (!map.ContainsKey(e))
map.Add(e, 0);
if (map[e] + 1 == threshold)
{
yield return e;
yield break;
}
map[e] = map[e] + 1;
}
}
}
you would use it like this:
var list = new List<int>() { 1,2,2,3,4,3,3 };
// list contains anything for 3 times?
var found = list.FirstRepeatedTimes(3).Any();
It could potentially consume some more memory, but it enumerates the list at most once. Is this Linq? The way I wrote it, it yields exactly 1 element (the first found), or no element, and you can further compose on top of it if you want. You could use FirstOfDefault()
instead of Any()
, and have then the found element or 0
(or null
if we deal with reference types). This way you have the choice.
It's just another way to see it.
試す
return
collection.Any(any => collection.Count(item => item.Equals(any)) == 3);
アイテムを単独でグループ化し、いずれかのグループに 3 つのアイテムが含まれているかどうかを評価すると、期待どおりの結果が得られます。
private bool ContainsTriple<T>(IList<T> items){
return items.GroupBy(i => i).Any(l => l.Count() == 3);
}
static void Main(string[] args)
{
List<string> col = new List<string>();
col.Add("a");
Console.WriteLine(Has_3(col));
Console.ReadKey();
col.Add("a");
Console.WriteLine(Has_3(col));
Console.ReadKey();
col.Add("a");
Console.WriteLine(Has_3(col));
Console.ReadKey();
col.Add("a");
Console.WriteLine(Has_3(col));
Console.ReadKey();
}
static bool Has_3(List<string> col)
{
return col.Count(x => x == "a").Equals(3);
}
私が最初に考えたのは、これはおそらく次のような Group() メソッドを使用して実行できるということでした:
var ints = new List<int>(new[] { 1, 2, 3, 4, 5, 6, 2, 2 });
var first = ints.GroupBy(n => n)
.Select(g => new { g.Key, Count = g.Count() })
.First(g => g.Count >= 3);
Console.WriteLine("Found {0} instances of {1}", first.Count, first.Key);
このスニペットは、3 つ以上の同じアイテムをチェックし、基準を満たす最初のアイテムを選択します。これを変更することをお勧めします。そして、整数ではなく特定のオブジェクトに適応させます。
拡張機能は次のとおりです。
public static bool ContainsNTimes<T>(this IEnumerable<T> sequence, T element, int duplicateCount)
{
if (element == null)
throw new ArgumentNullException("element");
if (!sequence.Any())
throw new ArgumentException("Sequence must contain elements", "sequence");
if (duplicateCount < 1)
throw new ArgumentException("DuplicateCount must be greater 0", "duplicateCount");
bool containsNTimes = sequence.Where(i => i.Equals(element))
.Take(duplicateCount)
.Count() == duplicateCount;
return containsNTimes;
}
使用法:
var list = new List<int>() { 1,2,2,3,4,3,3 };
// list contains 2 for 3 times?
bool contains2ThreeTimes = list.ContainsNTimes(2, 3);
// any element in the list iscontained 3 times (or more)?
bool anyContains3Times = list.Any(i => list.ContainsNTimes(i, 3));
Console.WriteLine("List contains 2 for 3 times? " + contains2ThreeTimes); // false
Console.WriteLine("Any element in the list is contained 3 times (or more)? " + anyContains3Times); // true (3)
遅延実行を使用するため、非常に効率的です。n 個の項目が見つかるまでシーケンスを列挙します。