Javascript-форум (https://javascript.ru/forum/)
-   Элементы интерфейса (https://javascript.ru/forum/dom-window/)
-   -   Объединение одинаковых значений в столбцах таблицы (https://javascript.ru/forum/dom-window/85700-obedinenie-odinakovykh-znachenijj-v-stolbcakh-tablicy.html)

Anat37 12.01.2024 10:26

Объединение одинаковых значений в столбцах таблицы
 
Здравствуйте, форумчане!

Есть массив вида {id:'1',name:'1',fid:''},{id:'2',name:'2',fid:'1'} ,{id:'3',name:'3',fid:''},{id:'4',name:'4',fid:'1' },{id:'5',name:'5',fid:'3'},{id:'6',name:'6',fid:' 3'}, и т.д..

Мне необходимо объединить ячейки в столбцах с одинаковыми fid.

Нашел https://javascript.ru/forum/dom-wind...bedinenie.html, но здесь объединение строк.

<script>
window.addEventListener("DOMContentLoaded", function() {
    var a = document.querySelectorAll("tr");
    [].forEach.call(a, function(c) {
        var a = c.querySelectorAll("td");
        [].reduce.call(a, function(a, b) {
            if (b.textContent != a.textContent) return b;
            a.colSpan++;
            c.removeChild(b);
            return a
        })
    })
});
  </script>


Поскольку я очень плохо разбираюсь в JS, простая замена в этом коде colSpan на rowSpan успеха не принесла даже если я вместо массива использую таблицу.

voraa 12.01.2024 10:34

Не совсем понятно
Цитата:

Сообщение от Anat37
Есть массив вида {id:'1',name:'1',fid:''},{id:'2',name:'2',fid:'1'} ,{id:'3',name:'3',fid:''},{id:'4',name:'4',fid:'1' },{id:'5',name:'5',fid:'3'},{id:'6',name:'6',fid:' 3'}, и т.д..

Мне необходимо объединить ячейки в столбцах с одинаковыми fid.

Приведите пример того, что должно получиться в результате в этом случае.

Anat37 12.01.2024 11:40

Вложений: 1
Прикрепил приблизительный файл.

Но изначально количество строк и количество одинаковых fid не известно, т.к. все зависит от выбора пользователя.

voraa 12.01.2024 12:08

Причем тут рисунок?
Вы пишете, что у вас есть массив
{id:'1',name:'1',fid:''},{id:'2',name:'2',fid:'1'} ,{id:'3',name:'3',fid:''},{id:'4',name:'4',fid:'1' },{id:'5',name:'5',fid:'3'},{id:'6',name:'6',fid:' 3'}, и т.д..
Его надо во что то преобразовать. Что то с чем то объединить (с одинаковыми fid.)
Вот есть {id:'1',name:'1',fid:''} и {id:'3',name:'3',fid:''}. Как их объединить? Что должно получиться в результате их объединения?

Anat37 12.01.2024 12:44

Извините, что плохо объясняю, думал картинка будет понятней.

Может так будет понятней:

ячейки в столбце fid с одинаковыми значениями объединить, если fid:'', их не объединять

т.е. объединить ячейки из массива

{id:'1',name:'1',fid:''},{id:'2',name:'2',fid:'1'} ,{id:'3',name:'3',fid:''},{id:'4',name:'4',fid:'1' },{id:'5',name:'5',fid:'3'},{id:'6',name:'6',fid:' 3'}, и т.д..

где fid:'1' и fid:'3'

Nexus 12.01.2024 12:51

Может что-то типа этого нужно (как еще можно "объединить" такие данные я не представляю)?
function groupBy(iterable, key) {
    const result = {};
    for (let item of iterable) {
        const itemKey = item[key] ?? '';

        result[itemKey] ??= [];
        result[itemKey].push(item);
    }

    return result;
}

var data = [{id:'1',name:'1',fid:''},{id:'2',name:'2',fid:'1'} ,{id:'3',name:'3',fid:''},{id:'4',name:'4',fid:'1' },{id:'5',name:'5',fid:'3'},{id:'6',name:'6',fid:' 3'}];

console.log(groupBy(data, 'fid'));//{"1":[{"id":"2","name":"2","fid":"1"},{"id":"4","name":"4","fid":"1"}],"3":[{"id":"5","name":"5","fid":"3"}],"":[{"id":"1","name":"1","fid":""},{"id":"3","name":"3","fid":""}]," 3":[{"id":"6","name":"6","fid":" 3"}]}

Anat37 12.01.2024 12:56

Может быть так будет понятней?

Мне бы таблицу получить из массива с объединением строк.

<table>
	<tbody>
		<tr>
			<td>2</td>
			<td>2</td>
			<td rowspan="2">1</td>
		</tr>
		<tr>
			<td>4</td>
			<td>4</td>
		</tr>
		<tr>
			<td>9</td>
			<td>9</td>
			<td>9</td>
		</tr>
		<tr>
			<td>5</td>
			<td>5</td>
			<td rowspan="3">3</td>
		</tr>
		<tr>
			<td>6</td>
			<td>6</td>
		</tr>
		<tr>
			<td>8</td>
			<td>8</td>
		</tr>
		<tr>
			<td>10</td>
			<td>10</td>
			<td>10</td>
		</tr>
	</tbody>
</table>

Nexus 12.01.2024 13:16

Так?
<div id="table-container"></div>

<style>
table, th, td {
  border: 1px solid;
  border-collapse: collapse;
}
</style>

<script>
    function groupBy(iterable, key) {
        const result = {};
        for (let item of iterable) {
            const itemKey = item[key] ?? '';

            result[itemKey] ??= [];
            result[itemKey].push(item);
        }

        return result;
    }

    function makeTableNode(groupedData, groupedByKey) {
        const values = Object.values(groupedData);
        const firstItem = values?.at(0)?.at(0);
        
        const table = document.createElement('table');
        if (!firstItem) {
            return table;
        }
        
        // thead
        const thead = document.createElement('thead');
        table.appendChild(thead);
        
        const tr = document.createElement('tr');
        thead.appendChild(tr);
        
        for (let key in firstItem) {
            const th = document.createElement('th');
            th.textContent = key;
            
            tr.appendChild(th);
        }
        
        // tbody
        const tbody = document.createElement('tbody');
        table.appendChild(tbody);
        
        values?.forEach(list => {
            list.forEach((item, index)=> {
                const tr = document.createElement('tr');
                tbody.appendChild(tr);
                
                for(let key in item) {
                    const isGroupByKey = key === groupedByKey;
                    if (index && isGroupByKey) {
                        continue;
                    }
                    
                    const td = document.createElement('td');
                    tr.appendChild(td);
                    
                    td.textContent = item[key];
                    if (isGroupByKey && list.length) {
                        td.rowSpan = list.length;
                    }
                }
            });
        });
        
        return table;
    }

    var data = [{id:'1',name:'1',fid:''},{id:'2',name:'2',fid:'1'} ,{id:'3',name:'3',fid:''},{id:'4',name:'4',fid:'1' },{id:'5',name:'5',fid:'3'},{id:'6',name:'6',fid:' 3'}];

    (data => {
        const container = document.querySelector('#table-container');
        if (!container) {
            return;
        }
        
        container.innerHTML = '';
        container.appendChild(
            makeTableNode(
                groupBy(data, 'fid'),
                'fid'
            )
        );
    })(data);
</script>

voraa 12.01.2024 13:19

Вопросы.
У вас в примере есть строки с fid:''. На рисунке строки с пустым fid не объединены. Что на самом деле надо делать с такими строками?

Могут ли строки с одинаковым fid идти не подряд?
({id:'2',name:'2',fid:'1'} ,{id:'3',name:'3',fid:''},{id:'4',name:'4',fid:'1' })
Что делать в этом случае? Строки с одинаковым fid переставлять так, что бы они шли подряд?

Что является входом? Некоторый массив или есть исходная таблица, которую надо реорганизовать?

Anat37 12.01.2024 13:29

Цитата:

Сообщение от voraa (Сообщение 554438)
Вопросы.
У вас в примере есть строки с fid:''. На рисунке строки с пустым fid не объединены. Что на самом деле надо делать с такими строками?

Могут ли строки с одинаковым fid идти не подряд?
({id:'2',name:'2',fid:'1'} ,{id:'3',name:'3',fid:''},{id:'4',name:'4',fid:'1' })
Что делать в этом случае? Строки с одинаковым fid переставлять так, что бы они шли подряд?

Что является входом? Некоторый массив или есть исходная таблица, которую надо реорганизовать?

Да, пустые fid не объединяются.

Да, строки с одинаковыми fid могут идти не друг за другом и их необходимо будет переставить.

Есть только массив, в котором количество строк изначально неизвестно и количество одинаковых fid также неизвестно, может быть 0, а может быть и 10.

Anat37 12.01.2024 13:38

Цитата:

Сообщение от Nexus (Сообщение 554437)
Так?
<div id="table-container"></div>

<style>
table, th, td {
  border: 1px solid;
  border-collapse: collapse;
}
</style>

<script>
    function groupBy(iterable, key) {
        const result = {};
        for (let item of iterable) {
            const itemKey = item[key] ?? '';

            result[itemKey] ??= [];
            result[itemKey].push(item);
        }

        return result;
    }

    function makeTableNode(groupedData, groupedByKey) {
        const values = Object.values(groupedData);
        const firstItem = values?.at(0)?.at(0);
        
        const table = document.createElement('table');
        if (!firstItem) {
            return table;
        }
        
        // thead
        const thead = document.createElement('thead');
        table.appendChild(thead);
        
        const tr = document.createElement('tr');
        thead.appendChild(tr);
        
        for (let key in firstItem) {
            const th = document.createElement('th');
            th.textContent = key;
            
            tr.appendChild(th);
        }
        
        // tbody
        const tbody = document.createElement('tbody');
        table.appendChild(tbody);
        
        values?.forEach(list => {
            list.forEach((item, index)=> {
                const tr = document.createElement('tr');
                tbody.appendChild(tr);
                
                for(let key in item) {
                    const isGroupByKey = key === groupedByKey;
                    if (index && isGroupByKey) {
                        continue;
                    }
                    
                    const td = document.createElement('td');
                    tr.appendChild(td);
                    
                    td.textContent = item[key];
                    if (isGroupByKey && list.length) {
                        td.rowSpan = list.length;
                    }
                }
            });
        });
        
        return table;
    }

    var data = [{id:'1',name:'1',fid:''},{id:'2',name:'2',fid:'1'} ,{id:'3',name:'3',fid:''},{id:'4',name:'4',fid:'1' },{id:'5',name:'5',fid:'3'},{id:'6',name:'6',fid:' 3'}];

    (data => {
        const container = document.querySelector('#table-container');
        if (!container) {
            return;
        }
        
        container.innerHTML = '';
        container.appendChild(
            makeTableNode(
                groupBy(data, 'fid'),
                'fid'
            )
        );
    })(data);
</script>

Да, приблизительно так.
Только с пустыми fid не объединять, а строки с fid:'3' - объединить.

voraa 12.01.2024 14:20

<head>
<style>
table {
	border: 1px solid black;
	border-collapse: collapse;
}
td {
	border: 1px solid black;
}
</style>
</head>
<body>
<table id="mytable"></table>
<script>
const data = [
{id:"1", name: "1", fid:""},
{id:"2", name: "2", fid:"1"},
{id:"3", name: "3", fid:"3"},
{id:"4", name: "4", fid:"4"},
{id:"5", name: "5", fid:"1"},
{id:"6", name: "6", fid:""},
{id:"7", name: "7", fid:"5"},
{id:"8", name: "8", fid:""},
{id:"9", name: "9", fid:"3"},
{id:"10", name: "10", fid:"1"},
{id:"11", name: "11", fid:""},
{id:"12", name: "12", fid:"5"}
];

function groupe (data) {
	const groupedata = [];
	for (const {id, name, fid} of data) {
		if (fid === "") {
			groupedata.push({rows:[{id, name}], fid});
		} else {
			const row = groupedata.find(row => row.fid === fid)
			if (!row) {
				groupedata.push({rows:[{id, name}], fid});
			} else {
				row.rows.push({id, name})
			}
		}
	}
	return groupedata;
}

function createtable (table, groupedata) {
	const thead = document.createElement('thead')
	thead.innerHTML = '<tr><th>id</th><th>name</th><th>fid</th></tr>';
	table.append(thead);
	const tbody = document.createElement('tbody');
	for (const {rows, fid} of groupedata) {
		for (let i = 0; i<rows.length; i++) {
			const row = document.createElement('tr');
			const tdid = document.createElement('td');
			const tdname = document.createElement('td');
			tdid.textContent = rows[i].id;
			tdname.textContent = rows[i].name;
			row.append(tdid,tdname);
			if (i === 0) {
				const tdfid = document.createElement('td');
				tdfid.textContent = fid;
				tdfid.rowSpan = rows.length;
				row.append (tdfid)
			}
			tbody.append (row);

		}		
	}
	table.append(tbody);
}

const groupedata = groupe(data);
createtable(document.getElementById('mytable'), groupedata);
</script>
<body>

Anat37 12.01.2024 14:49

Цитата:

Сообщение от voraa
<head>
<style>
table {
    border: 1px solid black;
    border-collapse: collapse;
}
td {
    border: 1px solid black;
}
</style>
</head>

СПАСИБО!!!!!!! ЭТО ТО, ЧТО НАДО!

Плюсик поставил, жаль что нельзя поставить 5.

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

voraa 12.01.2024 14:56

Цитата:

Сообщение от Anat37
А можно еще попросить проставить комментарии в какой строке что происходит.

Позже. Занят. Ухожу.

Anat37 12.01.2024 15:18

Цитата:

Сообщение от voraa (Сообщение 554443)
Позже. Занят. Ухожу.

Ничего страшного, я подожду, мне не горит я просто учусь.
К тому же завтра выходные, заниматься изучением будет некогда.

И еще вопрос:
Я немного изменил массив, оставил только fid:"1" для удобства

const data = [
{id:"2", name: "2", fid:"1"},
{id:"6", name: "2", fid:"1"},
{id:"2", name: "2", fid:"1"},
{id:"7", name: "7", fid:"1"},
{id:"10", name: "10", fid:"1"},
];


столбец fid:"1" получается объединенный, как продолжить объединение ячеек в других столбцах, например где name: "2" и id:"2" ?

соответственно, так же изначально неизвестно количество name: "2" и id:"2"

Если "криво" объяснил, пишите.

Nexus 12.01.2024 17:21

Anat37, если у вас id где-то повторяется, то у вас что-то не так с данными, потому что id предполагается уникальным.

Anat37 12.01.2024 17:26

Цитата:

Сообщение от Nexus (Сообщение 554445)
Anat37, если у вас id где-то повторяется, то у вас что-то не так с данными, потому что id предполагается уникальным.

id - это название

voraa 12.01.2024 18:04

Почему сразу не спросить все то, что нужно.
А то - сначала "для разминки" скажите как сделать то, потом усложним задание, сделайте это.
Спросите сразу все, что надо. Сделайте нормальный тестовый пример, что бы нам его не придумывать...

Anat37 15.01.2024 08:28

Цитата:

Сообщение от voraa (Сообщение 554447)
Почему сразу не спросить все то, что нужно.
А то - сначала "для разминки" скажите как сделать то, потом усложним задание, сделайте это.
Спросите сразу все, что надо. Сделайте нормальный тестовый пример, что бы нам его не придумывать...

Здравствуйте, уважаемый voraa!
1. Извините что сразу не ответил, в выходные занят сильно.
2. Нивкоем разе не хотел никого обидеть, я самостоятельно пытаюсь изучить JS и сам себе придумываю задания. Поэтому так и получилось.Извините еще раз.

Попробую объяснить задачу:
В таблице количество столбцов изначально неизвестно (может быть 1, а может быть и 10). В каждом столбце могут быть одинаковые строки.
Сначала идет объединение по первому столбцу, потом по второму, но объединяются строки, которые входят в объединенные строки первого столбца и т.д..
const data = [
{id:"2", name: "2", fid:"1"},
{id:"6", name: "2", fid:"1"},
{id:"2", name: "2", fid:"1"},
{id:"7", name: "7", fid:"1"},
{id:"10", name: "10", fid:"1"},
{id:"11", name: "11", fid:"2"},
{id:"12", name: "11", fid:"2"},
{id:"1", name: "1", fid:"2"},
{id:"10", name: "10", fid:"2"},
{id:"5", name: "5", fid:""},
{id:"3", name: "5", fid:""},
];


т.е. из этого объединение нет по строке вообще если первый столбец пустой,
{id:"10", name: "10", fid:"1"}, и {id:"10", name: "10", fid:"2"}, объединения по id и name нет, т.к. они в разных объединения первого столбца.
Надеюсь объяснил правильно.
И еще вопрос: можете посоветовать учебное пособие для самостоятельного изучения?
Здесь вот есть похожее, но из таблицы, а не из массива:
https://stackoverflow.com/questions/...ing-javascript

voraa 15.01.2024 09:22

Цитата:

Сообщение от Anat37
Сначала идет объединение по первому столбцу, потом по второму,

Вы столбцы с конца считаете? Обычно считают с начала.
Цитата:

Сообщение от Anat37
можете посоветовать учебное пособие для самостоятельного изучения?

Изучение чего? Если js, то https://learn.javascript.ru/
Цитата:

Сообщение от Anat37
В таблице количество столбцов изначально неизвестно (может быть 1, а может быть и 10). В каждом столбце могут быть одинаковые строки.

В такой постановке это не слишком простая задача

Anat37 15.01.2024 10:00

Цитата:

Сообщение от voraa (Сообщение 554451)
Вы столбцы с конца считаете? Обычно считают с начала.
Изучение чего? Если js, то https://learn.javascript.ru/

В такой постановке это не слишком простая задача

1. Конечно, лучше если fid будет первым.
2. Спасибо, сейчас перейду.
3. Тогда можно ограничить до 8 столбцов.

voraa 15.01.2024 10:18

Цитата:

Сообщение от Anat37
Тогда можно ограничить до 8 столбцов.

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

Anat37 15.01.2024 10:30

Цитата:

Сообщение от voraa (Сообщение 554453)
Не важно сколько. Главное, что не известно заранее, сколько их, соответственно не известны их имена. Поэтому объектами строки таблицы представлять проблематично.

А можно тогда для такого массива из трех столбцов
const data = [
{id:"2", name: "2", fid:"1"},
{id:"6", name: "2", fid:"1"},
{id:"2", name: "2", fid:"1"},
{id:"7", name: "7", fid:"1"},
{id:"10", name: "10", fid:"1"},
{id:"11", name: "11", fid:"2"},
{id:"12", name: "11", fid:"2"},
{id:"1", name: "1", fid:"2"},
{id:"10", name: "10", fid:"2"},
{id:"5", name: "5", fid:""},
{id:"3", name: "5", fid:""},
];


Мне бы только понять сам принцип.

Nexus 15.01.2024 18:40

Цитата:

Сообщение от Anat37
я самостоятельно пытаюсь изучить JS и сам себе придумываю задания

Так вы себе или нам задания придумываете?

У вас уже есть 2 примера готовых скриптов для разбора, изучайте оба и пробуйте написать то, что вам нужно. По ходу дела, если необходимо, задавайте вопросы.

Anat37 16.01.2024 08:24

Цитата:

Сообщение от Nexus (Сообщение 554465)
если необходимо, задавайте вопросы

Как правильно сюда добавить объединение по 'name'

container.innerHTML = '';
        container.appendChild(
            makeTableNode(
                groupBy(data, 'fid'),
                'fid'
            )


чтобы объединились 'name' в уже объединенных 'fid'?

Nexus 16.01.2024 14:26

Цитата:

Сообщение от Anat37
Как правильно сюда добавить

А его нужно не сюда добавлять, это просто идет очищение контейнера и добавление в него построенной таблицы.
Объединение происходит в функции groupBy.

Anat37 16.01.2024 14:31

Цитата:

Сообщение от Nexus
Объединение происходит в функции groupBy.

Я уже посмотрел примеры по этой функции, но везде идет группировка только по одному столбцу.

groupBy(data, ['fid'], ['name']) не работает

Nexus 16.01.2024 15:03

Anat37, начните с изучения основ js. Узнайте как работают функции, какие типы данных бывают и т.п.
От того, что вы в функцию, которая принимает 2 аргумента и вторым должна быть строка передадите 3 аргумента, где последние два - массивы, ничего не изменится.
Программирование так не работает, это не волшебство.


Часовой пояс GMT +3, время: 11:58.