Сведение двух таблиц в одну (сопоставляя колонки)

Moonwalker

Client
Регистрация
16.03.2016
Сообщения
1 364
Благодарностей
957
Баллы
113
Дано. Две таблицы, в каждой первая строка - заголовки. Сами колонки могут частично совпадать, частично отличаться.
Нужно из второй таблицы в первую добавить все строки, при этом все данные должны быть в соответствующей колонке. Если же при добавлении какой-то строки в ней есть колонки, которых не существовало в первой таблице, то в ней должна создаваться соответствующая колонка, ей должен устанавливаться заголовок и в соответствующую ячейку заноситься данные.
Т.е., цикл такой: берем строку, перебираем ячейки слева направо, если колонка с такими же данными (заголовком) уже существует, вставляем данные в соответствующую колонку, если не существует - создаем новую колонку, ставим ей заголовок, вписываем данные.
Надеюсь, понятно объяснил ))
Сниппет, наверное, должен быть не самый сложный (скорее всего, у кого-то даже есть), но я методом тыка (с шарпом лично я - пока только так) буду долго искать решение )))

ps. Подумал, что, наверное, потенциально можно сперва сразу обработать заголовки, создав недостающие колонки, а потом уже обрабатывать все строки с данными. Наверное, так даже правильнее будет.
 

BAZAg

Client
Регистрация
08.11.2015
Сообщения
1 764
Благодарностей
2 407
Баллы
113
C#:
IZennoTable tb1 =  project.Tables["tb1"];
tb1.AddRow(new[]{"один","два","три","пять","конец"}); // Строка заголовков
tb1.AddRow(new[]{"tb1_1","tb1_2","tb1_3","tb1_4","tb1_5" }); // Демо данные

IZennoTable tb2 =  project.Tables["tb2"];
tb2.AddRow(new[]{"два","семь","три","один"});// Строка заголовков
tb2.AddRow(new[]{"tb2_1","tb2_2","tb3_3","tb2_4"});// Демо данные

var title1 = tb1.GetRow(0).ToList();
var title2 = tb2.GetRow(0).ToList();

var hash = new HashSet<string>();
title1.ForEach(x=>hash.Add(x));
title2.ForEach(x=>hash.Add(x));

Func<HashSet<string>, Dictionary<string,string>> Title = (h) =>{
    var dic = new Dictionary<string,string>();
    h.ToList().ForEach(x=> dic[x] = string.Empty);
    return dic;
};

IZennoTable tb3 =  project.Tables["tb3"];
            tb3.AddRow(hash.ToArray());

for(int i=1;i<tb1.RowCount;i++){
    string[] row = tb1.GetRow(i).ToArray();
    var dic = Title(hash);
    for(int j=0;j<row.Length;j++) dic[title1[j]] = row[j];
    
    tb3.AddRow(dic.Values.ToArray());
}

for(int i=1;i<tb2.RowCount;i++){
    string[] row = tb2.GetRow(i).ToArray();
    var dic = Title(hash);
    for(int j=0;j<row.Length;j++)dic[title2[j]] = row[j];   
    tb3.AddRow(dic.Values.ToArray());
}
105158
 
  • Спасибо
Реакции: Dmitriy Ka и Moonwalker

Moonwalker

Client
Регистрация
16.03.2016
Сообщения
1 364
Благодарностей
957
Баллы
113
Глянул код, оно должно правильно работать, НО...
В коде колонки понятны. А по факту - нет. Т.е., это должно быть "универсальное" решение для разных колонок.
Для понимания цели. Я спарсил в несколько "этапов" товары. У одних одни колонки характеристик, у других - другие. Я даже не знаю, какие (а в сниппете - должен знать). Запустил, оно свелось в одну таблицу.
В общем, в теории - верно, на практике - не работа и выдает ошибку (Выполнение действия CSharp OwnCode. Последовательность не содержит соответствующий элемент),

PS. На Кворке пытался стукнуть, чтобы сказать спасибо, но там "закрыто".
 

BAZAg

Client
Регистрация
08.11.2015
Сообщения
1 764
Благодарностей
2 407
Баллы
113
Глянул код, оно должно правильно работать, НО...
В коде колонки понятны. А по факту - нет. Т.е., это должно быть "универсальное" решение для разных колонок.
Для понимания цели. Я спарсил в несколько "этапов" товары. У одних одни колонки характеристик, у других - другие. Я даже не знаю, какие (а в сниппете - должен знать). Запустил, оно свелось в одну таблицу.
В общем, в теории - верно, на практике - не работа и выдает ошибку (Выполнение действия CSharp OwnCode. Последовательность не содержит соответствующий элемент),

PS. На Кворке пытался стукнуть, чтобы сказать спасибо, но там "закрыто".
В этом случае нужны данные хотя бы 2 таблички по 3 строчки в каждой.
Честно, я не знаю что именно происходит - нужно посмотреть что происходит на каждом шаге.
Вариант универсальный при условии, что в первой строке находятся заголовки, не пустые ячейки.

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

Moonwalker

Client
Регистрация
16.03.2016
Сообщения
1 364
Благодарностей
957
Баллы
113
Да, видать, я вчера уже плохо видел или соображал )) Вечер пятницы, простительно.
Видать, не заметил вчера, что там в третью таблицу все собирается, а у меня она была, но с другим именем. Так что, почистил все от демоданных и поправил название таблицы, и все заработало )))) Надо больше отдыхать, в общем.

Про кворк понял. Про твою помощь знаю, но за помощь не проблема сказать спасибо разными способами ))) И "кнопка" - лишь один из них )))

ps. А есть вариант в первую таблицу просто добавлять, минуя третью? Условно, есть несколько файлов-таблиц, хочу их все объединить, думал грузануть первую, дальше все по очереди во вторую и из них уже добавлять в первую. Хотя, наверное, решу через перекидывание просто. Еще раз огромное спасибо!
 
Последнее редактирование:
  • Спасибо
Реакции: BAZAg

BAZAg

Client
Регистрация
08.11.2015
Сообщения
1 764
Благодарностей
2 407
Баллы
113
Да, видать, я вчера уже плохо видел или соображал )) Вечер пятницы, простительно.
Видать, не заметил вчера, что там в третью таблицу все собирается, а у меня она была, но с другим именем. Так что, почистил все от демоданных и поправил название таблицы, и все заработало )))) Надо больше отдыхать, в общем.

Про кворк понял. Про твою помощь знаю, но за помощь не проблема сказать спасибо разными способами ))) И "кнопка" - лишь один из них )))

ps. А есть вариант в первую таблицу просто добавлять, минуя третью? Условно, есть несколько файлов-таблиц, хочу их все объединить, думал грузануть первую, дальше все по очереди во вторую и из них уже добавлять в первую. Хотя, наверное, решу через перекидывание просто. Еще раз огромное спасибо!
Это мой косяк, нужно было описать что есть две таблицы на вход, и одна на выход.

Берем из папки пути к существующим 2-м таблицам из какой-то папки.
Просто привязываем все три таблицы к разным файлам - 1-2 к файлам с данными, 3-ю к пустому файлу.
Выполняем кубик.
После выполнения кубика -таблицы 1-2 привязываем к пустым файлам. Исходные таблицы-файлы перемещаем в другую папку как отработанные.
Завершение работы шаблона.

На следующей итерации выполнения снова выполняем привязку 1-2 к существующим файлам (файл с 3-й таблицы становится в 1-ю), к 2-й привязываем новый который нужно присоединить. В 3-ю - пустой.
Выполняя столько выполнений, сколько есть файлов - будут сопоставлены данные из всех файлов.

Но... Если файлы большие и их много - обработка может занять много времени.
Тогда, возможно есть смысл пробежаться сначала по всем таблицам, вытащить во всех таблицах заголовки.
Иметь только одну таблицу для результата.
И всегда одну таблицу на вход, данные из которой будут перемещаться во вторую в нужные ячейки.
В процессе просто привязывая исходную таблицу к разным файлам проходим в цикле до тех пор, пока не закончатся файлы.
 
  • Спасибо
Реакции: Moonwalker

Moonwalker

Client
Регистрация
16.03.2016
Сообщения
1 364
Благодарностей
957
Баллы
113
Не, не косяк, говорю же, вечер пятницы, мы с женой уже винишко открыли, я малек внимательность потерял )) Сегодня на свежую голову разобрался.
Да, сделаю через схему с перепривязкой таблиц по кругу, малек иначе, но уже придумал. Еще раз огромное спасибо за помощь )))
 
  • Спасибо
Реакции: BAZAg

Moonwalker

Client
Регистрация
16.03.2016
Сообщения
1 364
Благодарностей
957
Баллы
113
@BAZAg
А можно эти же способом решить такую задачу... Допустим, есть колонка в таблице, в которой собраны характеристики в формате:

{Характеристика}Название1{Значение}Значение1{Характеристика}Название2{Значение}Значение2{Характеристика}Название3{Значение}Значение3{Характеристика}Название4{Значение}Значение4

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

BAZAg

Client
Регистрация
08.11.2015
Сообщения
1 764
Благодарностей
2 407
Баллы
113
@BAZAg
А можно эти же способом решить такую задачу... Допустим, есть колонка в таблице, в которой собраны характеристики в формате:

{Характеристика}Название1{Значение}Значение1{Характеристика}Название2{Значение}Значение2{Характеристика}Название3{Значение}Значение3{Характеристика}Название4{Значение}Значение4

Соответственно, по такой же логике характеристики из нее разложатся по соответствующим колонкам. Если уже есть такая колонка (с таким названием), то добавляем в нее, если нет, то создаем новую (с заголовком).
Я не представляю как эффективно разбить строку {Характеристика}Название1{Значение}Значение1{Характеристика}Название2{Значение}Значение2{Характеристика}Название3{Значение}Значение3{Характеристика}Название4{Значение}Значение4 на ячейки. Если Вы сами её записываете в таком виде - то записывайте в каком-то json.

Что касается создания колонок и заголовков к ним - в момент заполнения таблички Вы уже должны знать какие у Вас там будут заголовки. Исходя из этого сначала первым проходом проходитесь по своим ячейкам, вытаскиваете заголовки в какой-либо временный список, потом удаляете там дубли.

И уже когда у Вас заголовки есть - тогда проходите табличку в цикле повторно, разбрасывая значения в столбцы, которые имеют в заголовке нужный текст.

Хотя... Я могу ошибаться, может быть кто-то другой из пользователей форума предложит более корректный/простой алгоритм.
 
  • Спасибо
Реакции: Moonwalker

Moonwalker

Client
Регистрация
16.03.2016
Сообщения
1 364
Благодарностей
957
Баллы
113
Так тут в целом алгоритм тот же, что работал выше, где таблицы сводили. Просто там были разные таблицы, а тут таблица одна, и данные "для раскладывания" берутся из определенного столбца.
Приложил файл-пример. Там на первом листе "исходник", на втором - "конечный результат".
Надписи {Характеристика} и {Значение} просто в качестве примера. "Разделители" могут быть любые, они просто ориентиры того, что здесь начинается новая характеристика, а здесь - ее значение (можно было бы просто построчно Название|Значение, но есть риск, что значение будет с переносом и "что-то пойдет не так").
ps. Но направление насчет в первый проход создаем колонки, во второй - раскидываем значения, понял. Буду думать...
 

Вложения

BAZAg

Client
Регистрация
08.11.2015
Сообщения
1 764
Благодарностей
2 407
Баллы
113
Так тут в целом алгоритм тот же, что работал выше, где таблицы сводили. Просто там были разные таблицы, а тут таблица одна, и данные "для раскладывания" берутся из определенного столбца.
Приложил файл-пример. Там на первом листе "исходник", на втором - "конечный результат".
Надписи {Характеристика} и {Значение} просто в качестве примера. "Разделители" могут быть любые, они просто ориентиры того, что здесь начинается новая характеристика, а здесь - ее значение (можно было бы просто построчно Название|Значение, но есть риск, что значение будет с переносом и "что-то пойдет не так").
ps. Но направление насчет в первый проход создаем колонки, во второй - раскидываем значения, понял. Буду думать...
Примерно так это может быть реализовано.:
C#:
var tb = project.Tables["tb"];
tb.AddRow(new[]{"Ссылка",    "Название",    "Описание",    "Характеристики"});
tb.AddRow(new[]{"link1",    "Name1",    "Description1",    "{Характеристика}Название1{Значение}Значение1{Характеристика}Название2{Значение}Значение2{Характеристика}Название3{Значение}Значение3{Характеристика}Название4{Значение}Значение4"});
tb.AddRow(new[]{"link2",    "Name2",    "Description2",    "{Характеристика}Название1{Значение}Значение1{Характеристика}Название2{Значение}Значение2{Характеристика}Название3{Значение}Значение3{Характеристика}Название4{Значение}Значение4"});
tb.AddRow(new[]{"link3",    "Name3",    "Description3",    "{Характеристика}Название1{Значение}Значение1{Характеристика}Название2{Значение}Значение2{Характеристика}Название3{Значение}Значение3{Характеристика}Название4{Значение}Значение4"});

Func<HashSet<string>, Dictionary<string,string>> Title = (h) =>{
    var dic = new Dictionary<string,string>();
    h.ToList().ForEach(x=> dic[x] = string.Empty);
    return dic;
};


var old_title = tb.GetRow(0).ToList();

var hash = new HashSet<string>();
old_title.ForEach(x=>hash.Add(x)); // Старые заголовки

// Определяюсь с заголовками
List<string[]> tb1 = new List<string[]>();
for(int i=1;i<tb.RowCount;i++) {
    tb1.Add(tb.GetRow(i).ToArray()); // добавляю строчку для дальнейшей обработки
    string cell = tb.GetCell(3, i); // Считываю ячеку D
    string[] fields1 = cell.Split(new[]{"{Характеристика}"},StringSplitOptions.RemoveEmptyEntries).ToArray(); // Получил все строки характеристик
    if(fields1.Length > 0) {
        for(int j=0;j<fields1.Length;j++) {
            string[] fields2 = fields1[j].Split(new[]{"{Значение}"},StringSplitOptions.RemoveEmptyEntries).ToArray();
            if(fields2.Length == 2) hash.Add(fields2.First()); // Сохраняем заголовок
        }
    }
}
var title1 = hash.ToArray(); // Новые заголовки

tb.Clear(); // Удаляю старые данные с таблицы
tb.AddRow(hash.ToArray()); // Добавляю новые заголовки


for(int i=0;i<tb1.Count;i++) {
    string[] row = tb1[i];   
    var dic = Title(hash);
    for(int j=0;j<row.Length;j++) dic[title1[j]] = row[j]; // первых 4 ячейки
    
    // Обработка характеристик
    string[] fields1 = row[3].Split(new[]{"{Характеристика}"},StringSplitOptions.RemoveEmptyEntries).ToArray(); // Получил все строки характеристик
    if(fields1.Length > 0) {
        for(int j=0;j<fields1.Length;j++) {
            string[] fields2 = fields1[j].Split(new[]{"{Значение}"},StringSplitOptions.RemoveEmptyEntries).ToArray();
            if(fields2.Length == 2) {
                dic[fields2.First()] = fields2.Last(); // Записываю данные в правильную ячейку
            }
        }
    }   
    tb.AddRow(dic.Values.ToArray()); // возвращаем результат
}
 
  • Спасибо
Реакции: djaga и Moonwalker

Moonwalker

Client
Регистрация
16.03.2016
Сообщения
1 364
Благодарностей
957
Баллы
113
Лайкнул авансом, был уверен, что сработает ))
Помня мою прошлую невнимательность, сразу убрал "демоданные". В общем, как и ожидалось, оно великолепно работает!
Слова благодарности. Пошел внедрять, надо в пару проектов )))
 
  • Спасибо
Реакции: BAZAg

М40

Новичок
Регистрация
24.03.2023
Сообщения
4
Благодарностей
4
Баллы
3
Лайкнул авансом, был уверен, что сработает ))
Помня мою прошлую невнимательность, сразу убрал "демоданные". В общем, как и ожидалось, оно великолепно работает!
Слова благодарности. Пошел внедрять, надо в пару проектов )))
Добрый день! Очень заинтересовал ваш опыт с zenno. Хотелось бы пообщаться. Можете написать в тг? Мой ник тг: vsz32255. Почта: [email protected]
 
  • Спасибо
Реакции: Phoenix78

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