Typstで著者順をランダムにする

:::note info
この記事は[Typst Advent Calendar 2024](https://qiita.com/advent-calendar/2024/typst) の6日目の記事です。 昨日は [@key271](https://qiita.com/key_271) さんの記事が公開されました。明日は[@tani_qiita](https://qiita.com/tani_qiita)さんの記事が公開される予定です。
:::

# はじめに
論文を書く際に、著者順で揉めることがあります。例えば経済学では著者順はアルファベット順になることが多いですが、他ではそうとも限りません。また、アルファベット順だとしても筆頭著者に過大なクレジットを与えてしまうという研究結果もあります。
そんなときには、著者順をランダムにしたいわけです。Ray ⓡ Robson (2017)は著者順をランダムにし、登録するようなシステムによって貢献を公平にできるということを主張しています。一部の学会では著者順をランダムにするツールが用意され、そこでランダム化された著者順を登録できます（https://www.aeaweb.org/journals/random-author-order ）。

この記事では著者順をランダムにする機能をTypstで直接実装する方法を書きます。

# コード
Typstのパッケージには乱数を発生させる[suiji](https://typst.app/universe/package/suiji)がありますのでそれを利用します。

```
#import "@preview/suiji:0.3.0": *
#let Random-Author(..authors, seeds:42, key:none, r-separator:" ⓡ ", separator:", ", last:", and ",dedup:false) = {
  let new_author = ()
  let i = 0
  for author in authors.pos() {
    // dictionary型はそのまま出力する
    if type(author) == "dictionary" {
      new_author.push(author)
      
    }
    // array型はシャッフルする
    if type(author) == "array" {
      let rng = gen-rng-f(seeds + i)
      let shuffled = shuffle-f(rng,author).at(1)
      new_author.push(shuffled)
      
      i += 1
    }
  }
  if key == none{
  return new_author.flatten()} //ネストしたarrayをネストしていないものに変換
  else {
    let new_authors_key = ()
    let n = new_author.len()
    for j in range(n) {
      if type(new_author.at(j)) == "dictionary" {
        if key in new_author.at(j) {
          new_authors_key.push(new_author.at(j).at(key))
        }
      }
      if type(new_author.at(j)) == "array" {
        let authors_set = ()
        for author in new_author.at(j) {
          if key in author{
          authors_set.push(author.at(key))
        }
        }
        if dedup == true {new_authors_key.push(authors_set)}
        else{
        new_authors_key.push(authors_set.join(r-separator)) // array型のものをシャッフルするので、ここでr-separatorによってわける 
      }
      } 
    }
    if dedup == true {
      new_authors_key.flatten().dedup().join(separator,last:last)
    }
    else {
    return new_authors_key.join(separator,last:last) //最後に順序が決まっているものとランダムなものを合成
  }
  }
}
```

`Random-Author(..authors)`シャッフルした著者のリストを出力します。引数はauthorsが著者のリストです。
オプション変数はseeds, key, r-separator, separator, last, dedupです。
seedsがランダム化のためのシードです。ここを日付にすればコンパイルする日によって著者順を変えるようにできます。他は後で説明します。


# 使い方

1. まず適当に著者を作りましょう。
    ```
    #let author1 =  (
      name: "Janet Doe",
      department: [Department of Mathematics],
      organization: [University of Exampleville],
      location: [Tennessee, TN 59341],
      email: "jdoe@math.ue.edu",
      url: "math.ue.edu/~jdoe",
     )
    
    #let author2 = (
      name: "John Smith",
      department: [Department of Statistics],
      organization: [University of Exampleville],
      )
    
    #let author3 = (
      name: "Kenneth Debreu",
      department: [Department of Economics],
      organization: [University of Exampleville],
      )
    
    
    #let author4 = (
      name: "Brabrabra",
      department: [Department of Economics],
      organization: [University of Exampleville],
    )
    
    ```
1. そのうえで次のようにします。[unequivocal-ams](https://typst.app/universe/package/unequivocal-ams)というパッケージを使用すれば、AMS風の論文を作成できます。
    ```
    #import "@preview/unequivocal-ams:0.1.2": ams-article, theorem, proof
    #show: ams-article.with(
    title: [Mathematical Theorems],
        authors: Random-Author((author1, author2, author3, author4)),
    abstract: lorem(100),
    bibliography: bibliography("refs.bib"),
    )
    ```
    
## 一部の著者順が決まっている場合
    


一部の分野では筆頭著者や最終著者だけは誰がなるか決まっている場合があります。そこで、一部の順序だけ固定して、残りの著者をシャッフルすることもできます。

```
#Random-Author(author1, (author2, author3), author4)
```

このようにすれば author4が最終著者に、author1が筆頭著者に固定されたうえで残りの著者の順番をシャッフルすることができます。

## 一部の情報だけを出力する。
名前だけを出力したい場合は次のようにします。

```
#Random-Author(author1, (author2, author3), author4, seeds:21, key:"name")
```

こうすれば Janet Doe, John Smith ⓡ Kenneth Debreu, and Brabrabra というように出力できます。ランダムにしたところは r-separatorで指定したものによって区切られます。その他はseparatorによって区切られます。

複数の著者の所属などが重複していて、一つだけを抜き出したいときには次のようにします。

```
#Random-Author(author1, (author2, author3), author4, seeds:21, key:"organization",dedup:true)
```
これで重複するものを削除できます。

# 参考文献

Debraj Ray ⓡ Arthur Robson (2018) "Certified Random: A New Order for Coauthorship"
*American Economic Review*, vol. 108, no. 2, February, pp. 489–520.