メモの日々


2019年04月05日(金) [長年日記]

[c++] 二分探索にはstd::partition_point()が使える

C++で二分探索を行いたいときはstd::lower_bound()を使っていたが、C++11で導入されたstd::partition_point()を使えばより柔軟に二分探索が行えることを知った。

lower_boundはpartition_pointの特殊なケースに過ぎない。

lower_boundは使えずpartition_pointなら使える例として、次を行うコードを示す。

  • 文字列長を基準にソートされた文字列配列から、特定の文字列長の文字列を二分探索で見つける
#include <algorithm>
#include <iostream>
#include <iterator>
#include <string>
#include <vector>

template<typename Langs>
std::string f(const Langs& langs, int length)
{
  const auto it = std::partition_point(
      std::cbegin(langs),
      std::cend(langs),
      [length](const auto& s) { return s.size() < length; });
  return it == std::end(langs) ? "" : *it;
}

int main()
{
  std::vector<std::string> langs = {
    "c", "c++", "go", "rust", "c#", "java", "swift", "python", "ruby", "javascript"
  };
  std::sort(
      std::begin(langs),
      std::end(langs),
      [](const auto& lhs, const auto& rhs) { return lhs.size() < rhs.size(); });
  std::cout << f(langs, 3) << std::endl;
  std::cout << f(langs, 7) << std::endl;
}
c++
javascript

2019年04月17日(水) [長年日記]

[web] テーブルにスクロールバーを付ける (2)

HTMLのtable要素で作るテーブルが縦に長い場合に、テーブルにスクロールバーを表示しかつスクロールしても行ヘッダが見えたままになるようにしたい。できればJavaScriptは使わずに。

14年前に同様のことをメモしたのだけれど、そのときの結果を今試しても想定通りには動かない。

CSSの「position: sticky」を使うと実現できるようなのでメモしておく。動作はFirefox 66とChrome 73で確認。

テーブルの高さが固定の例

テーブルの高さを固定にする場合はわりと簡単に実現できた。

スクロールバーはtable要素ではなくそれを囲むdiv要素が表示することに注意。HTMLとCSSを抜粋すると次のような感じ。

    <div class="table-wrapper">
        <table>
        ...
        </table>
    </div>
    .table-wrapper {
        display: inline-block;
        height: 300px;
        overflow: auto;
    }
    th {
        background-color: orange;
        position: sticky;
        top: 0;
    }
  • テーブルの高さを決める要素(上の例ではclassがtable-wrapperのdiv要素)にCSSでheightを設定し、table要素はこの要素の中に配置する。
  • th要素にCSSでstickyを設定する。
  • そのままだとスクロールした時にテーブルのヘッダとボディの文字が重なって表示されてしまうので、th要素には背景色を設定する。
  • table-wrapperクラスをinline-blockにしているのは、幅を内容(table要素)の幅に合わせるため。ただ、こうするとFirefox 66ではテーブルの幅が狭くなりすぎてしまう模様。

なお、Firefox 66ではヘッダのセル間に線を描画するためにtable要素のborder-collapseをseparateにする必要があった(上の抜粋には含めていない)。

テーブルの高さをブラウザのウィンドウの高さと連動させる例

テーブルの高さは、固定ではなくブラウザのウィンドウの高さと連動するようにしたいことが多いのでそのケースもメモ。

HTMLとCSSを抜粋する。HTMLは前の例と同じなのだけれど、table-wrapperを囲むdivにもスタイルを設定するのでその部分を含めて抜粋し直す。

    <div class="container">
        <h1>テーブルにスクロールバーを付ける</h1>
        <h2>テーブルの高さがウィンドウの高さに連動する例</h2>
        <div class="table-wrapper">
            <table>
            ...
            </table>
        </div>
    </div>
    .container {
        position: absolute;
        bottom: 10px;
        top: 10px;

        display: flex;
        align-items: start;
        flex-flow: column nowrap;
    }
    .table-wrapper {
        overflow: auto;
    }
    th {
        background-color: orange;
        position: sticky;
        top: 0;
    }
  • table-wrapperの親要素(上の例ではclassがcontainerのdiv要素)に「position: absolute」と「display: flex」を指定する。これにより、table-wrapperの高さがウィンドウの高さと連動するようになる。
  • table-wrapperにはinline-block指定やheightの指定は不要になる。