如题,在gender
列,有两个单元格都是M,怎样让这两个单元格合并?
library(DT)
df <- data.frame(
name = c("Alice", "Bob", "Charlie"),
gender = c("F", "M", "M"),
age = c(30, 31, 32),
stringsAsFactors = FALSE
)
datatable(df)
如题,在gender
列,有两个单元格都是M,怎样让这两个单元格合并?
library(DT)
df <- data.frame(
name = c("Alice", "Bob", "Charlie"),
gender = c("F", "M", "M"),
age = c(30, 31, 32),
stringsAsFactors = FALSE
)
datatable(df)
yuanfan 问题简单,逻辑也简单,但代码写起来简直是白了少年头,因为太琐碎了。要是放在平时,打死我也不愿写这种代码,费时间还攒不了什么经验值。正好赶上这周休病假差不多已经复活、加上这两天难得有一丝丝活雷锋精神、以及过两天就是学习雷锋纪念日,我就当积德行善、拼尽耐心写一段笨拙的 JS 代码吧:
function mergeRows(table) {
const tbody = table.querySelector('tbody');
if (!tbody) return;
// 先验证每一行的单元格数量是否相同;若不同,就不尝试合并了(可能已经合并过)
const rows = tbody.querySelectorAll('tr'), nrow = rows.length;
if (nrow < 2) return;
let ncol = rows[0].querySelectorAll(':scope > td').length;
for (let i = 1; i < nrow; i++) {
if (rows[i].querySelectorAll(':scope > td').length !== ncol) return;
}
let delCells = []; // 待移除的重复单元格
// 寻找每一列上下相同的相邻单元格,并用 rowspan 属性合并之
for (let j = 0; j < ncol; j++) {
// 第 j 列里的所有单元格
let cells = tbody.querySelectorAll('tr > td:nth-child(' + (j + 1) + ')');
let k = 0; // 计数,看有几个相邻单元格相同
for (let i = 1; i < nrow; i++) {
// 向顶层单元格添加 rowspan 属性
function addRowSpan(i) {
if (k === 0) return;
rows[i].querySelector(':scope > td:nth-child(' + (j + 1) + ')')
.setAttribute('rowspan', k + 1);
}
if (cells[i].innerHTML === cells[i - 1].innerHTML) {
k++; // 两行相同的话,计数器 k 加一
delCells.push(cells[i]); // 事后删除当前单元格
// 若到达最后一行,至此合并
if (i == rows.length - 1) addRowSpan(i - k);
} else {
// 若相邻两行不同,那么着手合并之前找到的相同单元格
addRowSpan(i - 1 - k);
k = 0; // 重置计数器
}
}
}
delCells.forEach(cell => cell.remove());
}
找到页面上所有表格,合并相同单元格:
document.querySelectorAll('table').forEach(table => mergeRows(table));
好累,我得喘会儿。
不知道 ChatGPT 会不会几秒钟就写出来了。我还没玩过这东西。
yihui
ChatGPT 交的作业,我完全不懂 JS,麻烦雷锋检查一下。
// Get the HTML table element
var table = document.getElementById("myTable");
// Loop through each row in the table (excluding the first row)
for (var i = 1; i < table.rows.length; i++) {
var currCell = table.rows[i].cells[1];
var prevCell = table.rows[i-1].cells[1];
// If the content of the current cell matches the content of the previous cell in the gender column,
// merge the current cell with the previous cell and update the rowspan of the previous cell
if (currCell.innerHTML === prevCell.innerHTML && currCell.innerHTML === "M") {
prevCell.rowSpan += 1;
currCell.style.display = "none";
}
}
我也不懂 JS,不过之前写的简单问答app就是在 ChatGPT 提示下编写出来的。
用 ChatGPT 写代码的缺点是,第一次给出的答案往往是一个不太精确但从 likelihood 角度最符合问题的答案。需要反复追问,直到给出相对符合设想的答案,这需要人类对具体的需求和编程语言的边界非常清楚,并且可以用自然语言精确描述出来(其实是一个不低的要求)。而 ChatGPT 的好处是可以提供一个大致可靠的框架和方向,比 Google 和 StackOverflow 提供的硬搜索结果要好得多,因为这里提供的「搜索」结果是根据现有知识合成的,针对性更强。
我目前的观察是,需要强逻辑的问题(比如涉及某种数学),或者需要创造性解决方案的问题(比如利用洞察力找近路),答案基本不可靠。另外就是生成的 JS 代码质量比 R 代码的质量更高一些,不知是否和训练数据量的大小以及训练所用代码的整体水平有关:GPT-3 以上应该都是使用了 GitHub 上的所有公开代码库训练的。
yihui 从 39 行代码精简到 37 行,删了一坨 querySelectorAll
,大快人心。放狗一搜还学会了一个新技能 [...集合]
创建数组(尽管在此例中毫无必要)。
function mergeRows(table) {
if (!table.tBodies) return;
const tbody = table.tBodies[0];
// 先验证每一行的单元格数量是否相同;若不同,就不尝试合并了(可能已经合并过)
const rows = [...tbody.rows], nrow = rows.length;
if (nrow < 2) return;
let ncol = rows[0].cells.length;
for (let i = 1; i < nrow; i++) {
if (rows[i].cells.length !== ncol) return;
}
let delCells = []; // 待移除的重复单元格
// 寻找每一列上下相同的相邻单元格,并用 rowspan 属性合并之
for (let j = 0; j < ncol; j++) {
// 第 j 列里的所有单元格
let cells = tbody.querySelectorAll('tr > td:nth-child(' + (j + 1) + ')');
let k = 0; // 计数,看有几个相邻单元格相同
for (let i = 1; i < nrow; i++) {
// 向顶层单元格添加 rowspan 属性
function addRowSpan(i) {
if (k > 0) rows[i].cells[j].rowSpan = k + 1;
}
if (cells[i].innerHTML === cells[i - 1].innerHTML) {
k++; // 两行相同的话,计数器 k 加一
delCells.push(cells[i]); // 事后删除当前单元格
// 若到达最后一行,至此合并
if (i == rows.length - 1) addRowSpan(i - k);
} else {
// 若相邻两行不同,那么着手合并之前找到的相同单元格
addRowSpan(i - 1 - k);
k = 0; // 重置计数器
}
}
}
delCells.forEach(cell => cell.remove());
}
document.querySelectorAll('table').forEach(table => mergeRows(table));
这个 ChatGPT 确实是学习的好向导。