Страницы

Поиск по вопросам

понедельник, 10 февраля 2020 г.

Получить уникальные значения списка

#c_sharp #linq


Есть список:

var list = new List {
    "строка",
    "строка22у", 
    "строкайцвцйй", 
    "текстцвцй", 
    "текст", 
    "текстыауке5"};


Нужно удалить элементы, которые содержат в себе другие элементы. Т.е. удалить строки
строка22у, строкайцвцйй, т.к. содержат первую строку и текстцвцй, текстыауке5 соответственно.
В результате останутся строка, текст.

Делаю так:

int removedCount;
do
{
    removedCount = 0;
    for (int i = 0; i < list.Count; i++)
    {
        removedCount += list.RemoveAll(x => x.Contains(list[i]) && x != list[i]);
    }
} while (removedCount != 0);


Есть ли более эффективный способ?
    


Ответы

Ответ 1



При большом количество строк (особенно если многие из них имеют одинаковые префиксы) вариант с построением префиксного дерева и поиску по нему должен работать гораздо быстрее. Однако и кода выходит гораздо больше. Вариант реализации. Метод поиска требуемых строк: private static List dfa(List list) { var result = new List(); State root = new State(); foreach (string word in list) { State state = root; foreach (char c in word) { state = state.get(c); } state.isFinal = true; } foreach (string word in list) { State state = root; int i = 0; for (; !state.isFinal && i < word.Length; i++) { state = state.get(word[i]); } if (i == word.Length) { result.Add(word); } } return result; } Вспомогательный класс состояния ДКА с учетом оптимизации: private class State { private Dictionary transitions; public bool isFinal = false; private char firstChar; private State firstState = null; public State get(char c) { if (firstState != null && firstChar == c) { return firstState; } if (firstState == null) { firstState = new State(); firstChar = c; return firstState; } if (transitions == null) { transitions = new Dictionary(); } if (transitions.ContainsKey(c)) { return transitions[c]; } State state = new State(); transitions.Add(c, state); return state; } }

Ответ 2



for (int i = 0; i < list.Count; i++) { for (int j = list.Count - 1; j >= 0; j--) { if (list[j].Contains(list[i]) && list[i] != list[j]) { list.RemoveAt(j); if (j < i) i--; } } }

Комментариев нет:

Отправить комментарий