Как удалить повторяющиеся комбинации из списка с помощью LINQ
У меня есть список строк, таких как
List<string> MyList = new List<string>
{
"A-B",
"B-A",
"C-D",
"C-E",
"D-C",
"D-E",
"E-C",
"E-D",
"F-G",
"G-F"
};
Мне нужно удалить дубликат из списка, т. е. если" A-B "и" B-A " существуют, то мне нужно сохранить только "A-B" (первая запись)
Таким образом, результат будет похож на
"A-B"
"C-D"
"C-E"
"D-E"
"F-G"
Есть ли способ сделать это с помощью LINQ?
6 ответов:
Это возвращает последовательность, которую вы ищете:
Короче говоря: разбейте каждую строку на символvar result = MyList .Select(s => s.Split('-').OrderBy(s1 => s1)) .Select(a => string.Join("-", a.ToArray())) .Distinct(); foreach (var str in result) { Console.WriteLine(str); }
-
на двухэлементные массивы. Отсортируйте каждый массив и снова соедините их вместе. Затем вы можете просто использоватьDistinct
, чтобы получить уникальные значения.Update: подумав немного больше, я понял, что вы можете легко удалить один из вызовов
Select
:var result = MyList .Select(s => string.Join("-", s.Split('-').OrderBy(s1 => s1).ToArray())) .Distinct();
Отказ от ответственности: это решение всегда будет сохранять значение "A-B" над "B-A", независимо от порядка, в котором они появляются в оригинале. последовательность.
Реализация IEqualityComparer witch возвращает true на равных ("A-B", "B-A"). И использовать перечисляемые.Distinct Метод
Вы можете использовать
Enumerable.Distinct(IEnumerable<TSource>, IEqualityComparer<TSource>)
перегрузка.Теперь вам просто нужно реализовать
IEqualityComparer
. Вот что вам нужно для начала:class Comparer : IEqualityComparer<String> { public bool Equals(String s1, String s2) { // will need to test for nullity return Reverse(s1).Equals(s2); } public int GetHashCode(String s) { // will have to implement this } }
Для реализации
Reverse()
смотрите Этот вопрос
Вам нужно реализовать IEqualityComparer следующим образом:
public class CharComparer : IEqualityComparer<string> { #region IEqualityComparer<string> Members public bool Equals(string x, string y) { if (x == y) return true; if (x.Length == 3 && y.Length == 3) { if (x[2] == y[0] && x[0] == y[2]) return true; if (x[0] == y[2] && x[2] == y[0]) return true; } return false; } public int GetHashCode(string obj) { // return 0 to force the Equals to fire (otherwise it won't...!) return 0; } #endregion }
Пример программы:
class Program { static void Main(string[] args) { List<string> MyList = new List<string> { "A-B", "B-A", "C-D", "C-E", "D-C", "D-E", "E-C", "E-D", "F-G", "G-F" }; var distinct = MyList.Distinct(new CharComparer()); foreach (string s in distinct) Console.WriteLine(s); Console.ReadLine(); } }
Результат:
"A-B" "C-D" "C-E" "D-E" "F-G"
Очень простой, но мог бы быть написан лучше (но это просто работает):
class Comparer : IEqualityComparer<string> { public bool Equals(string x, string y) { return (x[0] == y[0] && x[2] == y[2]) || (x[0] == y[2] && x[2] == y[0]); } public int GetHashCode(string obj) { return 0; } } var MyList = new List<String> { "A-B", "B-A", "C-D", "C-E", "D-C", "D-E", "E-C", "E-D", "F-G", "G-F" } .Distinct(new Comparer()); foreach (var s in MyList) { Console.WriteLine(s); }
int checkID = 0; while (checkID < MyList.Count) { string szCheckItem = MyList[checkID]; string []Pairs = szCheckItem.Split("-".ToCharArray()); string szInvertItem = Pairs[1] + "-" + Pairs[0]; int i=checkID+1; while (i < MyList.Count) { if((MyList[i] == szCheckItem) || (MyList[i] == szInvertItem)) { MyList.RemoveAt(i); continue; } i++; } checkID++; }