Удалить дубли в нескольких таблицах по одному столбцу

Mikhail B.

Moderator
Регистрация
23.12.2014
Сообщения
14 334
Благодарностей
5 431
Баллы
113
http://zennolab.com/discussion/threads/udalit-dubli-v-neskolkix-tablicax-po-odnomu-stolbcu.48561/

Так запихните колонку в список, создайте класс для листа с индексом таблицы и поудаляйте дубли, залейте назад по таблицам. Порядок строк должен сохраниться?
Мне нужно удалить дубли в колонках, но при этом что бы удалилась строка целиком. Ну как в екселе есть удаление дублей по колонкам.
 

orka13

Client
Регистрация
07.05.2015
Сообщения
2 167
Благодарностей
2 169
Баллы
113
Дернуло меня залезть в эту тему. Решил поизучать C# с практикой, вот готовые сниппеты с костылями. Оставлю потомкам. У меня опыта не очень в чистом кодинге, некоторые решения могут показаться смешными, но работает. Старался комментировать больше, сорян за орфографию :-). Файлы закинуть в папку \Папка_с_файлами\ возле файла шаблона, после работы оно их ЗАМЕНИТ свежими значениями. Для ускорения поиска дублей шаблон сортирует финальную таблицу по нужному столбцу, и сравнивает только соседние строки, не бегая каждый раз по всей таблице при поиске дублей:

C#:
IZennoTable Table_Big = project.Tables["Table_Big"];
Table_Big.ColSeparator = "Ћ";
IZennoTable Table1 = project.Tables["Table1"];
Table1.ColSeparator = "Ћ";
List<string> List_2 = new List<string>();
int Stolbec_Nomer = 3; // номер столбца поиска дублей (первый = 0).
List<string> List_3 = new List<string>();
string cell_old = "блаблабла любое уникальное значение !!! пщь!!";
string cell_new = "";
int Dele_ON = 0;

//читаем файлы в список:
var List = project.Lists["Файлы"];
string supportedExtensions = "*.xlsx,.xls";
foreach (string File in Directory.GetFiles(project.Directory+"\\Папка_с_файлами", "*.*", SearchOption.AllDirectories).Where(s => supportedExtensions.Contains(Path.GetExtension(s).ToLower()) && !s.Contains("~$") ))
{
    List.Add(File);
}
project.SendInfoToLog(List.Count + " шт. файлов нашли под обработку, быстрая версия шаблона с пересортировкой...", true);

//клеим таблицу каждого файла в одну большую таблицу Table_Big:
project.SendInfoToLog("Клеим таблицу каждого файла в одну большую таблицу Table_Big...", true);
for (int i=0; i<List.Count(); i++)
{
// Привязать временную таблицу Table1 к файлу:
Table1.Bind(List[i]);
int Table1_ColCount = Table1.ColCount;
    for (int c=0; c<Table1.RowCount; c++)
    {
        //добавляем в финальную таблицу только строки с нормальным количеством ячеек,
        //а то попадались битые таблицы, где в строке меньше ячеек чем обычно, и они НЕ сортируются и крашат проект.
        if (Table1.GetRow(c).Count() == Table1_ColCount)
        {
            string stroka = String.Join("Ћ", Table1.GetRow(c)) + "Ћ" + List[i];
            Table_Big.AddRow(stroka);
        }
    }
}

// сортируем таблицу через костыль
//http://zennolab.com/discussion/threads/sortirovat-kak-chisla-v-tablice.35147/
// номер столбца, по которому сортировать Stolbec_Nomer
List<string> tmpList = new List<string>(); // создаем темповый список
Enumerable.Range(0, Table_Big.RowCount).ToList().ForEach(x => tmpList.Add(string.Join("Ћ", Table_Big.GetRow(x)))); // добавляем в список все строки из таблицы, "Ћ" - разделитель столбцов
tmpList = tmpList.OrderBy(s => s.Split('Ћ')[Stolbec_Nomer].Length).ThenBy(s => s.Split('Ћ')[Stolbec_Nomer]).ToList(); // сортируем строки списка по возрастанию
Table_Big.Clear(); // очищаем таблицу
Enumerable.Range(0, tmpList.Count).ToList().ForEach(x => Table_Big.AddRow(tmpList[x])); // добавляем в таблицу  все строки из списка


//Чистим дубли:
project.SendInfoToLog(Table_Big.RowCount + " шт. строк в таблице Table_Big, чистим дубли...", true);
for (int d=0; d<Table_Big.RowCount; d++)
    {
        cell_new = Table_Big.GetCell(Stolbec_Nomer, d);  
        if (cell_new == cell_old && cell_new!="-")
        {
            Table_Big.DeleteRow(d);
            Dele_ON = 1;
            d--;          
        }
        else
        {
            if (Dele_ON == 1)
            {
                Table_Big.DeleteRow(d-1);
                d--;
            }
            Dele_ON = 0;
        }
cell_old = cell_new;              
    }
Второй вариант не нарушает структуры входящих файлов, но ооооочень долго будет обрабатывать шаг с поиском дублей, если там больше пары К строк:
C#:
IZennoTable Table_Big = project.Tables["Table_Big"];
Table_Big.ColSeparator = "Ћ";
IZennoTable Table1 = project.Tables["Table1"];
Table1.ColSeparator = "Ћ";
List<string> List_2 = new List<string>();
int Stolbec_Nomer = 3; // номер столбца поиска дублей (первый = 0).
List<string> List_3 = new List<string>();
string cell_old = "блаблабла любое уникальное значение !!! пщь!!";
string cell_new = "";
int Dele_ON = 0;

//читаем файлы в список:
var List = project.Lists["Файлы"];
string supportedExtensions = "*.xlsx,.xls";
foreach (string File in Directory.GetFiles(project.Directory+"\\Папка_с_файлами", "*.*", SearchOption.AllDirectories).Where(s => supportedExtensions.Contains(Path.GetExtension(s).ToLower()) && !s.Contains("~$") ))
{
    List.Add(File);
}
project.SendInfoToLog(List.Count + " шт. файлов нашли под обработку, быстрая версия шаблона с пересортировкой...", true);

//клеим таблицу каждого файла в одну большую виртуальную таблицу Table_Big (в памяти, без прявязки к файлу):
project.SendInfoToLog("клеим таблицу каждого файла в одну большую виртуальную таблицу Table_Big (в памяти, без прявязки к файлу)", true);
for (int i=0; i<List.Count(); i++)
{
// Привязать временную таблицу Table1 к файлу:
Table1.Bind(List[i]);
int Table1_ColCount = Table1.ColCount;
    for (int c=0; c<Table1.RowCount; c++)
    {
        //добавляем в финальную таблицу только строки с нормальным количеством ячеек,
        //а то попадались битые таблицы, где в строке меньше ячеек чем обычно, и они НЕ сортируются и крашат проект.
        if (Table1.GetRow(c).Count() == Table1_ColCount)
        {
            string stroka = String.Join("Ћ", Table1.GetRow(c)) + "Ћ" + List[i];
            Table_Big.AddRow(stroka);
        }
    }
}

// сортируем таблицу через костыль
//http://zennolab.com/discussion/threads/sortirovat-kak-chisla-v-tablice.35147/
// номер столбца, по которому сортировать Stolbec_Nomer
List<string> tmpList = new List<string>(); // создаем темповый список
Enumerable.Range(0, Table_Big.RowCount).ToList().ForEach(x => tmpList.Add(string.Join("Ћ", Table_Big.GetRow(x)))); // добавляем в список все строки из таблицы, "Ћ" - разделитель столбцов
tmpList = tmpList.OrderBy(s => s.Split('Ћ')[Stolbec_Nomer].Length).ThenBy(s => s.Split('Ћ')[Stolbec_Nomer]).ToList(); // сортируем строки списка по возрастанию
Table_Big.Clear(); // очищаем таблицу
Enumerable.Range(0, tmpList.Count).ToList().ForEach(x => Table_Big.AddRow(tmpList[x])); // добавляем в таблицу  все строки из списка


//Чистим дубли:
project.SendInfoToLog(Table_Big.RowCount + " шт. строк в таблице Table_Big, чистим дубли...", true);
for (int d=0; d<Table_Big.RowCount; d++)
    {
        cell_new = Table_Big.GetCell(Stolbec_Nomer, d);  
        if (cell_new == cell_old && cell_new!="-") // сравниваем на дубль, но просили если строка содержит "-", то ее не считать за дубль.
        {
            // если видим что дубль, то удаляем пока только эту строку с дублем, предыдущую строку (первую среди дублей) еще не удаляем, а то вдруг сейчас еще ее дублей найдем
            Table_Big.DeleteRow(d); //удаляем
            Dele_ON = 1; // утсанавливаем флаг 1, это значит что на следующем цикле мы будем знать что предыдущую строку удаляли
            d--;          
        }
        else // а елси строка не дубль
        {
            if (Dele_ON == 1) // то прверяем не удаляли ли мы перед етим дубль
            {
                Table_Big.DeleteRow(d-1); // и если удаляли, то аж теперь удалим ту первую дублирующую строку.
                d--;
            }
            Dele_ON = 0; // обнулим наш флаг
        }
cell_old = cell_new; // пропишем для следующего цикла значение старой ячейки, чтобы ему было с чем сравнивать.              
    }

// Дубли мы удалили, теперь бы как-то собрать обратно строки с большой таблицы в мелкие (по метке в последнем столбце):
project.SendInfoToLog(Table_Big.RowCount + " шт. строк в таблице Table_Big после чистки дублей, теперь бы как-то собрать обратно строки с большой таблицы в мелкие (по метке в последнем столбце)...", true);
for (int i=0; i<List.Count(); i++)
{
Table1.Bind(List[i]);
Table1.Clear();
Table1.ColSeparator = "Ћ";
int Col_Last_Number = Table_Big.ColCount - 1;
    for (int c=0; c<Table_Big.RowCount; c++)
    {
        string cell_Metka = Table_Big.GetCell(Col_Last_Number, c);
        if (cell_Metka==List[i])
        {
        List_3.Clear();
        //Получаем строку, добавляем ее в список чтобы удалить последний элемент-ячейку с меткой:
        List_3.AddRange(Table_Big.GetRow(c));
        //Удаляем последний элемент списка
        List_3.RemoveAt(Col_Last_Number);
        string row_new = String.Join("Ћ", List_3);
        Table1.AddRow(row_new);
        }
    }
}
 
Последнее редактирование:
  • Спасибо
Реакции: Mikhail B.

Ikigai

Client
Регистрация
13.12.2016
Сообщения
275
Благодарностей
27
Баллы
28
Ребята , а как удалить дубли в одной таблице по первому столбцу. Т.е.
Есть таблица в ней в первом столбце дублируются названия компаний, но другие столбцы отличаются, нужно удалить дубли по названия

Все, нашел уже есть такая опция) Вопрос снят
 

Meteorburn

Client
Регистрация
23.05.2016
Сообщения
1 452
Благодарностей
565
Баллы
113
Метод для удаление дубликатов в таблице ZennoPoster по определённому столбцу.

C#:
using System.Collections;

public static IZennoTable RemoveDuplicateRows(IZennoTable dTable, int colName)
{
    // Initialize special collections to remove duplicates
    Hashtable hTable = new Hashtable();
    ArrayList cleanList = new ArrayList();

    // If hTable do not contain column value, than write to clean list, otherwise continue
    for (int i=0; i < dTable.RowCount; i++) {
        var drow = dTable.GetRow(i);
        if (!hTable.Contains(drow.ElementAt(colName))) {
                cleanList.Add(drow);
                hTable.Add(drow.ElementAt(colName), string.Empty);
        }
    }
       
    // Clear source table
    dTable.Clear();

    // Add to source table rows without duplicates
    foreach (IEnumerable<string> dRow in cleanList) {
        dTable.AddRow(dRow);
    }
       
    // Datatable which contains unique records will be return as output
    return dTable;
}
или так

C#:
using System.Collections;

public static void RemoveDuplicateRows(IZennoTable dTable, int colName)
{
    // Initialize special collections to remove duplicates
    Hashtable hTable = new Hashtable();
    ArrayList cleanList = new ArrayList();

    // If hTable do not contain column value, than write to clean list, otherwise continue
    for (int i=0; i < dTable.RowCount; i++) {
        var drow = dTable.GetRow(i);
        if (!hTable.Contains(drow.ElementAt(colName))) {
                cleanList.Add(drow);
                hTable.Add(drow.ElementAt(colName), string.Empty);
        }
    }
       
    // Clear source table
    dTable.Clear();

    // Add to source table rows without duplicates
    foreach (IEnumerable<string> dRow in cleanList) {
        dTable.AddRow(dRow);
    }
}
 

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