Имеет следующий код:
Dictionary<int, List<int>> dic = new Dictionary<int, List<int>>();
dic.Add(1, new List<int>());
dic[1].Add(10);
dic[1].Add(6);
dic.Add(2, new List<int>());
dic[2].Add(9);
dic[2].Add(7);
dic[2].Add(7);
dic.Add(3, new List<int>());
dic[3].Add(9);
dic[3].Add(10);
dic[3].Add(9);
dic.Add(4, new List<int>());
dic[4].Add(6);
// Will give KVPs of Key 1 and 4
var under7 = dic.Where(T => T.Value.Any(Y => Y < 7));
Поэтому я легко нашел, какие KVP содержат значение менее 7.
Мой вопрос в том, как я могу перебирать словарь, чтобы узнать KVP, которые имеют повторяющиеся значения с ключом, следующим за другим ключом (уже по порядку).
Как и в этом, нужно подобрать:
dic.Add(2, new List<int>());
dic[2].Add(9);
dic[2].Add(7); // MATCH
dic[2].Add(7); // MATCH
Но не это:
dic.Add(3, new List<int>());
dic[3].Add(9); // NOT MATCH
dic[3].Add(10);
dic[3].Add(9); // NOT MATCH
Есть ли способ сделать это с помощью LINQ?
Пытался дать ему шаг, используя что-то вроде ниже, но очевидно, что это не работает.
// Should give KVP of Key 2 but not 3
var dupVals = dic.Where(T => T.Value.Aggregate( (i1, i2) => i1 == i2));
var dupVals = dic.Where(T => T.Value.Any( (i1,i2) => i1 == i2 ));
EDIT: Итак, у Сергея был ответ:
var result = dic.Where(kvp =>
kvp.Value.Skip(1).Zip(kvp.Value, (x, y) => x == y).Any(b => b));
Но как именно это работает?
Вы можете проверить, имеет ли список два последовательных дубликата с
list.Skip(1).Zip(list, (x,y) => x == y).Any(b => b)
Сделайте это для каждого значения в словаре:
// yep, you can use this pretty initializer
var dic = new Dictionary<int, List<int>> {
{ 1, new List<int> { 10, 6 }},
{ 2, new List<int> { 9, 7, 7 }},
{ 3, new List<int> { 9, 10, 9 }},
{ 4, new List<int> { 6 }}
};
var result = dic.Where(kvp =>
kvp.Value.Skip(1).Zip(kvp.Value, (x, y) => x == y).Any(b => b));
Объяснение: Расширение Enumerable.Zip
применяет указанную функцию (x,y) => x == y
к соответствующим элементам из двух последовательностей. Эти две последовательности - это список, а тот же список сдвинут на один элемент вперед. Т.е. вы применяете функцию для index
и index + 1
элемент одного и того же списка. Эта функция дает результат сравнения элементов. Таким образом, Zip вернет последовательность значений true
и false
зависимости от равенства последовательных элементов. Если в результате есть какой-либо true
результат, у вас есть два последовательных дубликата.
Шаг за шагом: рассмотрите следующий список 9, 10, 9, 7, 7
. Если вы пропустите первый элемент в этом списке, вы получите последовательность 10, 9, 7, 7
. Замедление этих двух последовательностей приведет к появлению следующих пар элементов (вы должны пометить соответствующие элементы - первый и первый, второй и второй и т.д.): (10, 9), (9, 10), (7,9), (7,7)
. Следующий шаг применяется к каждой паре (x,y) => x == y
. Результат будет false, false, false, true
. Как вы можете видеть, последняя пара (четвертый элемент из первой последовательности и четвертый элемент из второй последовательности) имеет равные элементы, поэтому она производит true
. И последнее - проверять, действительно ли какая-либо из пар создала true
.
Zip
является одним из наиболее часто используемых методов расширения семейства Linq. Таким образом, небольшое объяснение будет иметь большое значение для будущих посетителей. В противном случае это отличный ответ.
dic[1].Add(10);
)?