Нужна помощь в поиске строки в списке c#

arbplv

Client
Регистрация
28.03.2020
Сообщения
373
Благодарностей
23
Баллы
18
Добрый вечер.
Задача.
Спарсить данные с сайта, который обновляется где-то раз в 2-3 секунды и положить в список все эти данные. Данные должны быть уникальными.
Я сделал бесконечный цикл через while с задержкой в 100 мс, System.Threading.Thread.Sleep(100).
Все данные складываю в список и на выходе у меня получается, типа такого:
10:05:59:508 строка 1
10:05:59:854 строка 1
10:06:00:157 строка 2
10:06:00:506 строка 2
10:06:00:854 строка 1
10:06:01:202 строка 3
10:06:01:481 строка 3
10:06:01:772 строка 3
10:06:02:181 строка 4
10:06:02:473 строка 3
10:06:03:002 строка 2
10:06:03:351 строка 2
10:06:03:588 строка 5
10:06:03:868 строка 5
10:06:04:106 строка 3
10:06:04:384 строка 2
10:06:04:648 строка 5
10:06:04:914 строка 1
10:06:05:202 строка 4
10:06:05:720 строка 1

Если посмотреть на данные то там есть дубли, мне нужно как то проверять на наличие дублей, и в случае нахождения дублей нужно не заносить эти данные в список.
Данные заношу с помощью переменной, сначала создал HtmlElementCollection и циклом выдергиваю нужные мне данные и заношу в список. К примеру, переменную назовем var а список InfoList. Получается мне нужно проверять есть ли переменная var в списке InfoList.
Подскажите как это сделать?
Через .Contains не подходит, тк мне нужно точное сравнение. Что то запутался с синтаксисом, выручайте плиз. У меня мысли такие, но чет не могу до конца сообразить:
идет код и в переменной на этом этапе уже лежат данные
var = "проверяемые данные";
//делаем цикл из всех строчек что лежат уже в списке, чтобы проверить каждую
for (int i =0; i<InfoList.Count(); i++)
{
if(var == InfoList ) // если есть повторение, то сбрасываем цикл и ничего не проверяем
{break;}

else if(var != InfoList && i == (InfoList.Count - 1)) // если не равно всем значениям и все перебрали (i равен максимальному значению) то записываем строчку в конец
{InfoList.Add(var);}

}

Но чет не работает, по разному пробовал, понимаю что для многих простая задача, но я чет не соображу уже...
нужно проверить все строчки и если нет совпадений, занести эти данные.
Спс за помощь и время что прочитали мою писанину...
 

doc

Client
Регистрация
30.03.2012
Сообщения
8 605
Благодарностей
4 596
Баллы
113

arbplv

Client
Регистрация
28.03.2020
Сообщения
373
Благодарностей
23
Баллы
18
метод .Contains для списка ищет точное совпадение
Если у меня 3 строки;
слово1 слово2
слово1 слово2 слово3
слово1 слово2 слово3 слово4
И через .Contains мы ищем 2 строку (слово1 слово2 слово3), то этот метод выдаст нам и 2 и 3 строку.
 

arbplv

Client
Регистрация
28.03.2020
Сообщения
373
Благодарностей
23
Баллы
18
Если через метод, то наиболее близкий для меня, это наверное .Equals, но сильно большой разницы с == я не знаю, т.к. не так хорошо знаю C#. Тут вопрос как это написать, логикой то я понимаю что нужно сделать. Проверить переменную на соответствие с каждой строчкой списка, и если нет совпадения, записать. Вопрос наверное больше по синтаксису... Вот думаю...
 

doc

Client
Регистрация
30.03.2012
Сообщения
8 605
Благодарностей
4 596
Баллы
113
Если у меня 3 строки;
слово1 слово2
слово1 слово2 слово3
слово1 слово2 слово3 слово4
И через .Contains мы ищем 2 строку (слово1 слово2 слово3), то этот метод выдаст нам и 2 и 3 строку.
я говорю о методе списка, а не тестовой переменной. Он не выдаёт строки, он отдаёт true или false в зависимости от того, есть строка в списке или нет
InfoList.Contains
 
  • Спасибо
Реакции: arbplv

Alexmd

Client
Регистрация
10.12.2018
Сообщения
1 021
Благодарностей
1 383
Баллы
113
C#:
var list = итоговый_список;
var portion = порция_спаршенных_данных;
foreach(string str in portion)
    if(list.IndexOf(str) >= 0)
        list.Add(str);
 
  • Спасибо
Реакции: arbplv

ZComand

Client
Регистрация
02.02.2016
Сообщения
57
Благодарностей
63
Баллы
18
10:05:59:508 строка 1
10:05:59:854 строка 1
10:06:00:157 строка 2
10:06:00:506 строка 2
10:06:00:854 строка 1
10:06:01:202 строка 3
10:06:01:481 строка 3
10:06:01:772 строка 3
10:06:02:181 строка 4
10:06:02:473 строка 3
10:06:03:002 строка 2
10:06:03:351 строка 2
10:06:03:588 строка 5
10:06:03:868 строка 5
10:06:04:106 строка 3
10:06:04:384 строка 2
10:06:04:648 строка 5
10:06:04:914 строка 1
10:06:05:202 строка 4
10:06:05:720 строка 1
Если каждая строка в твоем списке содержит в начале дату тогда нужно сначала от нее избавиться. примерно так:
Поиск дубля строки в списке без учета даты в начале строки:
List<string> InfoList = new List<string> {
                "10:05:59:508 строка 1",
                "10:05:59:854 строка 1",
                "10:06:00:157 строка 2",
                "10:06:00:506 строка 2",
                "10:06:00:854 строка 1",
                "10:06:01:202 строка 3",
                "10:06:01:481 строка 3",
                "10:06:01:772 строка 3",
                "10:06:02:181 строка 4",
                "10:06:02:473 строка 3",
                "10:06:03:002 строка 2",
                "10:06:03:351 строка 2",
                "10:06:03:588 строка 5",
                "10:06:03:868 строка 5",
                "10:06:04:106 строка 3",
                "10:06:04:384 строка 2",
                "10:06:04:648 строка 5",
                "10:06:04:914 строка 1",
                "10:06:05:202 строка 4",
                "10:06:05:720 строка 1"
            };
string searchString = "строка 1";
if (!InfoList.Any(x => Regex.Match(x, "(?<=[0-9]{3} ).*").Value == searchString))// (?<=[0-9]{3} ).* - эта регулярка удаляет дату и пробел после нее потом идет сравнение строк.
   InfoList.Add(searchString);
 
  • Спасибо
Реакции: arbplv

arbplv

Client
Регистрация
28.03.2020
Сообщения
373
Благодарностей
23
Баллы
18
C#:
var list = итоговый_список;
var portion = порция_спаршенных_данных;
foreach(string str in portion)
    if(list.IndexOf(str) >= 0)
        list.Add(str);
Можешь пояснить строку list.IndexOf(str) >= 0,
Вот на пальцах и переменной, а не списке.
string str1 = "Hello world!";
string str2 = "lo";
int pos = str1.IndexOf(str2);
// pos = 3
.IndexOf возвращает индекс с отсчетом от нуля первого вхождения указанного символа Юникода или строки в пределах данного экземпляра. Получается в нашем случае, если есть вхождение, то вернется номер строки где есть это вхождение, а это больше 0 и запишется наша новая строка. Правильно я тебя понял?
 

Alexmd

Client
Регистрация
10.12.2018
Сообщения
1 021
Благодарностей
1 383
Баллы
113
Можешь пояснить строку list.IndexOf(str) >= 0,
Вот на пальцах и переменной, а не списке.
string str1 = "Hello world!";
string str2 = "lo";
int pos = str1.IndexOf(str2);
// pos = 3
.IndexOf возвращает индекс с отсчетом от нуля первого вхождения указанного символа Юникода или строки в пределах данного экземпляра. Получается в нашем случае, если есть вхождение, то вернется номер строки где есть это вхождение, а это больше 0 и запишется наша новая строка. Правильно я тебя понял?
Верно.


Так ищется полное совпадение строки в списке, просто чуток пошустрее, чем перебором в цикле.
Но, если надо вырезать дату из строки, то тут больше подойдет пример со сравнением, предложенный выше, потому что нецелесообразно преобразовывать весь список, чтобы искать там по индексу.
Я сперва подумал, что дата - это тоже результат парсинга, а не время занесения строки в список, вот и предложил, а потом присмотрелся, но было поздно...
 

arbplv

Client
Регистрация
28.03.2020
Сообщения
373
Благодарностей
23
Баллы
18
Если каждая строка в твоем списке содержит в начале дату тогда нужно сначала от нее избавиться. примерно так:
Поиск дубля строки в списке без учета даты в начале строки:
List<string> InfoList = new List<string> {
                "10:05:59:508 строка 1",
                "10:05:59:854 строка 1",
                "10:06:00:157 строка 2",
                "10:06:00:506 строка 2",
                "10:06:00:854 строка 1",
                "10:06:01:202 строка 3",
                "10:06:01:481 строка 3",
                "10:06:01:772 строка 3",
                "10:06:02:181 строка 4",
                "10:06:02:473 строка 3",
                "10:06:03:002 строка 2",
                "10:06:03:351 строка 2",
                "10:06:03:588 строка 5",
                "10:06:03:868 строка 5",
                "10:06:04:106 строка 3",
                "10:06:04:384 строка 2",
                "10:06:04:648 строка 5",
                "10:06:04:914 строка 1",
                "10:06:05:202 строка 4",
                "10:06:05:720 строка 1"
            };
string searchString = "строка 1";
if (!InfoList.Any(x => Regex.Match(x, "(?<=[0-9]{3} ).*").Value == searchString))// (?<=[0-9]{3} ).* - эта регулярка удаляет дату и пробел после нее потом идет сравнение строк.
   InfoList.Add(searchString);
с регуляркой понятно, а вот дальше не очень, давай разберем поподробнее.
1. проверяемая строка у нас лежит в переменной searchString
2. с помощью вот этого кусочка Regex.Match(x, "(?<=[0-9]{3} ).*").Value мы получаем чистую строку без времени. А что за х фигурирует? если посмотреть документацию то
Regex(string sourceString, string sourceRegex,) дальнейшие перегрузки не используем. Получается х это номер строки которая получается из нашего списка, так?
3. также не понятно и вот этот сравнение (x => зачем мы так сравниваем?
4. дальше мы ставим отрицание !InfoList... , а чем отличаться будет если напишем вот так ...Value != search...
Заранее извини если вопросы покажутся глупыми, спс
 

arbplv

Client
Регистрация
28.03.2020
Сообщения
373
Благодарностей
23
Баллы
18
Верно.


Так ищется полное совпадение строки в списке, просто чуток пошустрее, чем перебором в цикле.
Но, если надо вырезать дату из строки, то тут больше подойдет пример со сравнением, предложенный выше, потому что нецелесообразно преобразовывать весь список, чтобы искать там по индексу.
Я сперва подумал, что дата - это тоже результат парсинга, а не время занесения строки в список, вот и предложил, а потом присмотрелся, но было поздно...
я конечную строку собираю из 3х переменных, могу с датой, могу без даты. Мне очень важна скорость, прям очень))), потому и время в миллисекундах. IndexOf вот этот метод он быстрее ищет, нежели перебор в цикле, верно? Я вообще думал чистить список каждые например 1000 строк, чтобы ускорить процесс. Данные мне нужны буквально несколько часов, потом можно их удалить.
 

arbplv

Client
Регистрация
28.03.2020
Сообщения
373
Благодарностей
23
Баллы
18
Верно.


Так ищется полное совпадение строки в списке, просто чуток пошустрее, чем перебором в цикле.
Но, если надо вырезать дату из строки, то тут больше подойдет пример со сравнением, предложенный выше, потому что нецелесообразно преобразовывать весь список, чтобы искать там по индексу.
Я сперва подумал, что дата - это тоже результат парсинга, а не время занесения строки в список, вот и предложил, а потом присмотрелся, но было поздно...
а метод InfoList.Contains не будет еще быстрее IndexOf ?
 

ZComand

Client
Регистрация
02.02.2016
Сообщения
57
Благодарностей
63
Баллы
18
также не понятно и вот этот сравнение (x => зачем мы так сравниваем?
В моем варианте используется System.Linq (IndexOf из той же оперы )), Contains туда же) Так вот Метод Any у списка смотрит есть ли в списке какое либо совпадение в соответствии с предикатом. Где предикатом является лямда ф-ция. ( x => x == searchString). Посмотри на ютубе ролики по запросу C# LINQ примеры )). Там много интересного.

Относительно времени проверки Все решения которые тут написаны работают одинаково быстро. В моем варианте будет обрабатываться условие быстрее если не использовать регулярки вообще. ( x => x == searchString).

дальше мы ставим отрицание !InfoList... , а чем отличаться будет если напишем вот так ...Value != search...
Возвращаемым значением предиката)), с точки зрения логики ни чем.

а метод InfoList.Contains не будет еще быстрее IndexOf ?
Так же в твоем кейсе метод Contains использовать не вариант так как он проверяет вхождение подстроки в строку. Ты уже писал об этом:
И через .Contains мы ищем 2 строку (слово1 слово2 слово3), то этот метод выдаст нам и 2 и 3 строку.
А тебе нужно сравнивать 2 строки целиком это делается через ==

в борьбе за скорость:

C#:
List<string> searchStringsList = new List<string>
            {
                "10:05:59:508 строка 1",
                "10:06:00:506 строка 2"
            };
            // В случае параллельной обработки данных придется использовать ConcurrentQueue - это потокобезопасный список так скажем ))
            //Если использовать простой List тогда будет ошибка параллельного доступа к данным, а использование lock все усилия по увеличению скорости сведет на нет
            ConcurrentQueue<string> InfoList = new ConcurrentQueue<string>();
            //Используем TPL
            searchStringsList.AsParallel().ForAll(
                //предикат где Х это строка из списка searchStringsList
                x => {
                    if (InfoList.Any(
                        //второй предикат обозначим за Y, это строка из списка InfoList)
                        y => y != x)
                    )
                    {
                        //если не нашли точного вхождения данных то добавляем строку в список результата
                        InfoList.Enqueue(x);
                    }
                    }
                );
 
  • Спасибо
Реакции: SHILY, arbplv и Alexmd

arbplv

Client
Регистрация
28.03.2020
Сообщения
373
Благодарностей
23
Баллы
18
Вопрос решился с помощью метода .IndexOf.
Всем спасибо за внимание!
 

Кто просматривает тему: (Всего: 1, Пользователи: 0, Гости: 1)