草庐IT

javascript - 给定一个数据矩阵,计算 html rowspan 和 colspan

coder 2024-07-22 原文

我有一个如下所示的稀疏矩阵,由数据单元格 (1..9) 和空单元格 (=0) 组成:

[
    [ 1, 2, 0, 3 ],
    [ 0, 4, 0, 0 ],
    [ 5, 6, 7, 8 ],
]

我想将其显示为 html 表格,但不应有空单元格 - 它们应该被相邻数据单元格的行和列跨度“覆盖”:

<table border=1 cellpadding=10>
    <tr>
        <td rowspan=2>1</td>
        <td colspan=2>2</td>
        <td>3</td>
    </tr>
    <tr>
        <td colspan=3>4</td>
    </tr>
    <tr>
        <td>5</td>
        <td>6</td>
        <td>7</td>
        <td>8</td>
    </tr>
</table>

(这是一种可能的实现方式,我们也可以在第二行使用 colspan=4 而没有 rowspan)。

生成实际的 html 不是问题,但我无法编写算法来计算数据单元格的行和列跨度。

编辑:仍在为此寻找答案。仅使用 colspans 并将每个数据单元与其左侧/右侧的空单元连接起来似乎很简单。但是,我希望单元格尽可能呈方形,因此答案也应包括行跨度逻辑。谢谢!

EDIT2:到目前为止所有的答案都总结在这里:http://jsfiddle.net/ThQt4/

最佳答案

您需要考虑一些事项。

如果您总是喜欢正方形而不是最大的形状,您最终可能会得到很多单行和单列,因为矩形总是以正方形开头。并且正方形或矩形只有在左上角有值时才能开始。

考虑这个数组:

[1, 2, 3, 4, 5],
[7, 0, 0, 0, 0],
[0, 0, 0, 0, 0],
[1, 2, 0, 0, 5]

如果您选择正方形而不是最大的形状,您最终会得到一个正方形和三列

[1] [2] [3] [4] [5] instead of [1] [2] [3] [4] [5]
[  7  ] [ ] [ ] [ ]            [        7        ]
[     ] [ ] [ ] [ ]            [                 ]

此外,您最终可能会得到空的单个单元格:

[1, 1, 2, 0],   gives   [1] [1] [  2  ]
[3, 0, 0, 0],           [         ] [?] <---
[0, 0, 0, 5],           [    3    ] [5]
[0, 0, 0, 1]            [         ] [1]

此处最大的正方形大小为 3x3,从 3 开始。如果您先声明 3x3,然后声明从 2 开始的行,您将以 [?] 大于 5 的空单元格结束。

最后一件事,如果你在顶行或左列中有零,你也可能会遇到麻烦:

                                             V
[1, 0, 0, 2],  will leave you with  [  1  ] [?] [2]
[0, 0, 3, 4],                       [     ] [3] [4]
[0, 5, 6, 7]                    --->[?] [5] [6] [7]

也就是说,也许您的数组没有那么复杂,也许您不介意空单元格。无论哪种方式,用您的规范解决这个难题都很有趣。我的解决方案遵循以下规则:

1) 方 block 先行。

2) 大小很重要。越大越好

3) 行和列:大小很重要。最大的先。

4) Colspan 遍历 rowspan

Fiddle

var maxv = arr.length;
var maxh = arr[0].length;
var rsv = [];
var rsh = [];
pop_arr();
var shape;
try_sq();
try_rect();
try_loose();


//TRY SQUARES FIRST
function try_sq() {
    var sv, sh;
    shape = [];
    for (sv = 0; sv < maxv - 1; sv++) {
        for (sh = 0; sh < maxh - 1; sh++) {
            if (arr[sv][sh] === 0 || rsv[sv][sh] > -1 || rsh[sv][sh] > -1) {
                continue;
            }
            check_sq(sv, sh);
        }
    }
    if (shape.length > 0) {
        occu();
    }
}


//TRY RECTANGLES
function try_rect() {
    var sv, sh;
    var rect = false;
    do {
        shape = [];
        for (sv = 0; sv < maxv; sv++) {
            for (sh = 0; sh < maxh; sh++) {
                if (arr[sv][sh] === 0 || rsv[sv][sh] > -1 || rsh[sv][sh] > -1) continue;
                check_rec(sv, sh);
            }
        }
        if (shape.length > 0) {
            occu();
        } else {
            rect = false;
        }
    } while (rect === true);
}

//TRY LOOSE
function try_loose() {
    var sv, sh;
    //SET THE 1x1 with value
    for (sv = 0; sv < maxv; sv++) {
        for (sh = 0; sh < maxh; sh++) {
            if (arr[sv][sh] !== 0 && (rsv[sv][sh] == -1 || rsh[sv][sh] == -1)) {
                rsv[sv][sh] = 1;
                rsh[sv][sh] = 1;
            }
        }
    }
    //SEARCH FOR rectangles wit no value
    var rect = true;
    do {
        shape = [];
        for (sv = 0; sv < maxv; sv++) {
            for (sh = 0; sh < maxh; sh++) {
                if (arr[sv][sh] !== 0 || (rsv[sv][sh] > -1 || rsh[sv][sh] > -1)) {
                    continue;
                }
                rect = check_loose(sv, sh);
            }
        }
        if (shape.length > 0) occu();
        else {
            rect = false;
        }
    } while (rect === true);
}


//check SINGLES 
function check_loose(start_v, start_h) {
    var vd, hd, iv, ih, rect;
    var hor = ver = 1;
    var horb = 0;
    var mxv = maxv - 1;
    var mxh = maxh - 1;
    rect = true;
    vd = start_v + ver;
    hd = start_h + hor;

    //check horizontal
    for (sh = start_h + 1; sh <= mxh; sh++) {
        if (arr[start_v][sh] !== 0 || rsh[start_v][sh] > -1) {
            break;
        }
        hor++;
    }
    //check vertical
    for (iv = start_v + 1; iv <= mxv; iv++) {
        if (arr[iv][start_h] !== 0 || rsh[iv][start_h] > -1) {
            break;
        }
        ver++;
    }
    if (hor > ver || hor == ver) {
        shape.unshift({
            0: (hor),
            1: [start_v, start_h, 1, hor]
        });
        return true;
    } else if (ver > hor) {
        shape.push({
            0: (ver),
            1: [start_v, start_h, ver, 1]
        });
        return true;
    }
    return false;
}




//check SQUARE        
function check_sq(start_v, start_h) {
    if (arr[start_v + 1][start_h] !== 0) {
        return false;
    }
    if (arr[start_v][start_h + 1] !== 0) {
        return false;
    }
    var vd, hd, sv, sh, square;
    var hor = ver = 1;
    var mxv = maxv - 1;
    var mxh = maxh - 1;
    //CHECK DIAGONAL
    do {
        square = true;
        vd = start_v + ver;
        hd = start_h + hor;
        //diagonal OK
        if (arr[vd][hd] !== 0) {
            if (hor == 1) {
                if (ver == 1) {
                    return false;
                }
                square = false;
                break;
            }
        }
        //check horizontal
        for (sh = start_h; sh <= hd; sh++) {
            if (arr[vd][sh] !== 0) {
                square = false;
                break;
            }
        }
        if (square === false) break;
        //check vertical
        for (sv = start_v; sv <= vd; sv++) {
            if (arr[sv][hd] !== 0) {
                square = false;
                break;
            }
        }
        if (square === false) break;
        hor++;
        ver++;
    } while (square === true && vd < mxv && hd < mxh);
    //SQUARE OK
    if (hor > 1 && ver > 1 && hor == ver) {
        shape.push({
            0: (hor * ver),
            1: [start_v, start_h, ver, hor]
        });
    }
}


//check RECTANGLE
function check_rec(start_v, start_h) {
    var vd, hd, iv, ih, rect;
    var hor = ver = 1;
    var horb = 0;
    var mxv = maxv - 1;
    var mxh = maxh - 1;
    rect = true;
    vd = start_v + ver;
    hd = start_h + hor;

    //check horizontal
    if (start_h < maxh) {
        for (sh = start_h + 1; sh <= mxh; sh++) {
            if (arr[start_v][sh] !== 0 || rsh[start_v][sh] > -1) break;
            hor++;
        }
    }
    //check vertical
    if (start_v < maxv) {
        for (iv = start_v + 1; iv <= mxv; iv++) {
            if (arr[iv][start_h] !== 0 || rsh[iv][start_h] > -1) break;
            ver++;
        }
    }
    if (hor == 1 && ver == 1) return false;
    if (hor > ver || hor == ver) {
        shape.unshift({
            0: (hor),
            1: [start_v, start_h, 1, hor]
        });
        return true;
    } else {
        shape.push({
            0: (ver),
            1: [start_v, start_h, ver, 1]
        });
        return true;
    }
    return false;
}


//FIND LARGEST SHAPE
function occu() {
    var le = shape.length;
    for (var i = 0; i < le; i++) {
        var b = Math.max.apply(Math, shape.map(function (v) {
            return v[0];
        }));
        for (var j = 0; j < shape.length; j++) {
            if (shape[j][0] == b) break;
        }
        var c = shape.splice(j, 1);
        claim(c[0][1]);
    }
}


//CLAIM SHAPE
function claim(sh) {
    var iv, ih;
    for (iv = sh[0]; iv < sh[0] + sh[2]; iv++) {
        for (ih = sh[1]; ih < sh[1] + sh[3]; ih++) {
            if (rsv[iv][ih] > -1 || rsh[iv][ih] > -1) return false;
        }
    }
    for (iv = sh[0]; iv < sh[0] + sh[2]; iv++) {
        for (ih = sh[1]; ih < sh[1] + sh[3]; ih++) {
            rsv[iv][ih] = 0;
            rsh[iv][ih] = 0;
        }
    }
    rsv[sh[0]][sh[1]] = sh[2];
    rsh[sh[0]][sh[1]] = sh[3];
}

function pop_arr() {
    var em = [];
    em[0] = arr[0].concat();
    for (var i = 0; i < maxh; i++) {
        em[0][i] = -1;
    }
    for (i = 0; i < maxv; i++) {
        rsv[i] = em[0].concat();
        rsh[i] = em[0].concat();
    }
}

关于javascript - 给定一个数据矩阵,计算 html rowspan 和 colspan,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23362746/

有关javascript - 给定一个数据矩阵,计算 html rowspan 和 colspan的更多相关文章

  1. ruby - 解析 RDFa、微数据等的最佳方式是什么,使用统一的模式/词汇(例如 schema.org)存储和显示信息 - 2

    我主要使用Ruby来执行此操作,但到目前为止我的攻击计划如下:使用gemsrdf、rdf-rdfa和rdf-microdata或mida来解析给定任何URI的数据。我认为最好映射到像schema.org这样的统一模式,例如使用这个yaml文件,它试图描述数据词汇表和opengraph到schema.org之间的转换:#SchemaXtoschema.orgconversion#data-vocabularyDV:name:namestreet-address:streetAddressregion:addressRegionlocality:addressLocalityphoto:i

  2. ruby - 使用 Vim Rails,您可以创建一个新的迁移文件并一次性打开它吗? - 2

    使用带有Rails插件的vim,您可以创建一个迁移文件,然后一次性打开该文件吗?textmate也可以这样吗? 最佳答案 你可以使用rails.vim然后做类似的事情::Rgeneratemigratonadd_foo_to_bar插件将打开迁移生成的文件,这正是您想要的。我不能代表textmate。 关于ruby-使用VimRails,您可以创建一个新的迁移文件并一次性打开它吗?,我们在StackOverflow上找到一个类似的问题: https://sta

  3. ruby-on-rails - Rails - 一个 View 中的多个模型 - 2

    我需要从一个View访问多个模型。以前,我的links_controller仅用于提供以不同方式排序的链接资源。现在我想包括一个部分(我假设)显示按分数排序的顶级用户(@users=User.all.sort_by(&:score))我知道我可以将此代码插入每个链接操作并从View访问它,但这似乎不是“ruby方式”,我将需要在不久的将来访问更多模型。这可能会变得很脏,是否有针对这种情况的任何技术?注意事项:我认为我的应用程序正朝着单一格式和动态页面内容的方向发展,本质上是一个典型的网络应用程序。我知道before_filter但考虑到我希望应用程序进入的方向,这似乎很麻烦。最终从任何

  4. ruby-on-rails - 渲染另一个 Controller 的 View - 2

    我想要做的是有2个不同的Controller,client和test_client。客户端Controller已经构建,我想创建一个test_clientController,我可以使用它来玩弄客户端的UI并根据需要进行调整。我主要是想绕过我在客户端中内置的验证及其对加载数据的管理Controller的依赖。所以我希望test_clientController加载示例数据集,然后呈现客户端Controller的索引View,以便我可以调整客户端UI。就是这样。我在test_clients索引方法中试过这个:classTestClientdefindexrender:template=>

  5. ruby-on-rails - 使用一系列等级计算字母等级 - 2

    这里是Ruby新手。完成一些练习后碰壁了。练习:计算一系列成绩的字母等级创建一个方法get_grade来接受测试分数数组。数组中的每个分数应介于0和100之间,其中100是最大分数。计算平均分并将字母等级作为字符串返回,即“A”、“B”、“C”、“D”、“E”或“F”。我一直返回错误:avg.rb:1:syntaxerror,unexpectedtLBRACK,expecting')'defget_grade([100,90,80])^avg.rb:1:syntaxerror,unexpected')',expecting$end这是我目前所拥有的。我想坚持使用下面的方法或.join,

  6. ruby-on-rails - 如果 Object::try 被发送到一个 nil 对象,为什么它会起作用? - 2

    如果您尝试在Ruby中的nil对象上调用方法,则会出现NoMethodError异常并显示消息:"undefinedmethod‘...’fornil:NilClass"然而,有一个tryRails中的方法,如果它被发送到一个nil对象,它只返回nil:require'rubygems'require'active_support/all'nil.try(:nonexisting_method)#noNoMethodErrorexceptionanymore那么try如何在内部工作以防止该异常? 最佳答案 像Ruby中的所有其他对象

  7. ruby - 为什么 SecureRandom.uuid 创建一个唯一的字符串? - 2

    关闭。这个问题需要detailsorclarity.它目前不接受答案。想改进这个问题吗?通过editingthispost添加细节并澄清问题.关闭8年前。Improvethisquestion为什么SecureRandom.uuid创建一个唯一的字符串?SecureRandom.uuid#=>"35cb4e30-54e1-49f9-b5ce-4134799eb2c0"SecureRandom.uuid方法创建的字符串从不重复?

  8. ruby-on-rails - Rails - 从另一个模型中创建一个模型的实例 - 2

    我有一个正在构建的应用程序,我需要一个模型来创建另一个模型的实例。我希望每辆车都有4个轮胎。汽车模型classCar轮胎模型classTire但是,在make_tires内部有一个错误,如果我为Tire尝试它,则没有用于创建或新建的activerecord方法。当我检查轮胎时,它没有这些方法。我该如何补救?错误是这样的:未定义的方法'create'forActiveRecord::AttributeMethods::Serialization::Tire::Module我测试了两个环境:测试和开发,它们都因相同的错误而失败。 最佳答案

  9. ruby - Ruby 有 `Pair` 数据类型吗? - 2

    有时我需要处理键/值数据。我不喜欢使用数组,因为它们在大小上没有限制(很容易不小心添加超过2个项目,而且您最终需要稍后验证大小)。此外,0和1的索引变成了魔数(MagicNumber),并且在传达含义方面做得很差(“当我说0时,我的意思是head...”)。散列也不合适,因为可能会不小心添加额外的条目。我写了下面的类来解决这个问题:classPairattr_accessor:head,:taildefinitialize(h,t)@head,@tail=h,tendend它工作得很好并且解决了问题,但我很想知道:Ruby标准库是否已经带有这样一个类? 最佳

  10. ruby - 用 Ruby 编写一个简单的网络服务器 - 2

    我想在Ruby中创建一个用于开发目的的极其简单的Web服务器(不,不想使用现成的解决方案)。代码如下:#!/usr/bin/rubyrequire'socket'server=TCPServer.new('127.0.0.1',8080)whileconnection=server.acceptheaders=[]length=0whileline=connection.getsheaders想法是从命令行运行这个脚本,提供另一个脚本,它将在其标准输入上获取请求,并在其标准输出上返回完整的响应。到目前为止一切顺利,但事实证明这真的很脆弱,因为它在第二个请求上中断并出现错误:/usr/b

随机推荐