2026年4月27日月曜日

Schema.org(構造化データ)を学ぶ

現在Googleが推奨する構造化データを学んでみた話

タイトル通りですが基本的に一般人は気にする必要はないです。理由は3つほど

  • ・検索のページランク自体には直結しない
  • ・なのに記述を間違えると怒られる
  • ・リッチリザルトは実務系しか強化されていない

リッチリザルトと構造化データの関係

リッチリザルト レポートの概要
「https://support.google.com/webmasters/answer/7552505?hl=ja」

構造化データ自体はだいぶ前から存在しており、情報を構造化して機械が理解しやすい様にすると考えれば基本的には十分です。

リッチリザルトは構造化データの「対象となる一部」から検索結果の見た目を強化する機能です。
これ自体はページランクに影響しないが検索結果が装飾される事でクリック率が上がり結果的にSEOに繋がる。

つまり、「構造化データ」は様々な情報を整理できるがそもそもリッチリザルトは一部しか対応してないので一般人が使うような内容には影響がないというわけです。

Schema.orgってなに?

構造化データを定義(Structured Data)している所です。
構造化データを定義を入れる時にこのサイトに構造情報があるという「"@context": "https://schema.org",」を指定します。
ですが現状ここしか指定出来ません。保証される構造情報を提供してるのがここしかないからです。

元々は Google・Microsoft・Yahoo・Yandex が共同で立ち上げたプロジェクトですが現状はほぼgoogleの影響で決まります。
そのためgoogleが構造化を推奨を強くしているわけです。

余り良くない事もあります。

リッチリザルトが実務ベースが強く、構造化データは多くの情報を定義出来るにお金になるProduct(商品)、JobPosting(求人)、LocalBusiness(店舗)、Recipe(レシピ)と言った所しかリッチリザルトされません。
FQAなども信頼の高いサイト以外は無意味になったし、How-toも廃止。
百歩譲ってリッチリザルトが実利を取るのはいいですが、構造化データ自体10年以上ほぼ変わらない構造化データなどがあります。

例えばVideoGameなどの構造はボードゲームなどの物理ゲームをベースに作られほぼ更新がありません。
ゲームアイテムの説明をするページを作る時にgameitemというプロパティはあるがメインに置くカテゴリが無いです。
存在しないアイテムなどの場合は「"mainEntity": {"@type": "Thing","name": "ゲームのアイテム名",」のようにThingしかないです。
また、同様にその説明に入れる情報は階層としてPropertyValueにするしかありません。

更に2026年今現在のAIに構造化データを作らせるとProductなどとあり得ない提案をして来たりします。
しかしそれらは実際の商品に対するものなのでゲームアイテムがリッチリザルトなどされるとショップを偽装するサイトとして評価が下がります。
ここらへんが最初に書いた通りの「一般人は気にする必要はないです」という事です。
あと記述も厳密でhtmlと違いカンマ一つ違うだけでエラーします。
変に構造化データを入れてページの信頼を落とすより、構造化を入れない方が大半の一般人には正しいです。

当然ある程度は構造化データに更新を求めて提案がされていますが主にgoogleがそれを取り合っていない為、構造化の追加もされてないのが今現在です。閑話休題。

構造化の構造について

さて話を戻して構造データについて。

Thing (最上位:すべての基本)
┃
┣━ Action (動作:検索、購入、予約など)
┃
┣━ CreativeWork (著作物・創作物)
┃   ┣━ Article (記事)
┃   ┃   ┗━ NewsArticle (ニュース記事)
┃   ┣━ Recipe (レシピ)
┃   ┣━ WebPage (ウェブページ)
┃   ┗━ Movie (映画)
┃
┣━ Event (イベント)
┃   ┣━ BusinessEvent (ビジネスイベント)
┃   ┗━ EducationEvent (教育イベント)
┃
┣━ Organization (組織)
┃   ┣━ Corporation (企業)
┃   ┗━ LocalBusiness (地域のお店・施設)
┃       ┣━ FoodEstablishment (飲食店)
┃       ┃   ┗━ Restaurant (レストラン)
┃       ┗━ Store (小売店)
┃
┣━ Person (人物)
┃
┣━ Place (場所)
┃   ┗━ AdministrativeArea (行政区画:市町村など)
┃
┣━ Product (製品・商品)
┃
┗━ Intangible (無形のもの)
    ┣━ ListId (リストの識別)
    ┃   ┗━ ItemList (リスト全般)
    ┃       ┗━ BreadcrumbList (パンくずリスト)
    ┣━ Enumeration (列挙型:在庫状況など)
    ┣━ Language (言語)
    ┗━ StructuredValue (構造化された値:評価、価格など)
        ┣━ AggregateRating (合計評価)
        ┗━ PriceSpecification (価格詳細)
    

全部ではありませんが主要なツリー構造はこういう感じです。
共通プロパティは「name (名前), url (URL), image (画像), description (説明)
これらを使ってサイトの構造を定義します。初手は

<script type="application/ld+json">
{
  "@context": "https://schema.org",
  ...内容
</script>

これです。
ページの情報はhtmlのその一つであっても個々に見ようとするので基本的には「"@graph": [...]」が必要になります。
更に言えばgraphで繋いでも情報が分散するのでidが必要になります。
面倒臭そうに見えますか?はい、実際に面倒臭いです。

ページ構造で必要なのは主に

  • パンくずリスト(最低限これだけあればいい)
  • メインコンテンツ(mainEntity)

形式的には

  <script type="application/ld+json">
  {
    "@context": "https://schema.org",
    "@graph": [
      {
        "@type": "BreadcrumbList",
        "itemListElement": [
          {"@type": "ListItem", "position": 1, "name": "top", "item": "url"},
          {"@type": "ListItem", "position": 2, "name": "階層", "item": "url"},
          {"@type": "ListItem", "position": 3, "name": "現在", "item": "現url"},
        ]
      },
      {
        "@type": "コンテンツのタイプ",
        "url": "現url",
        "name": "ページのタイトル",
        "description": "ページの説明",
        "mainEntity": {
          ...内容
        }
      }
    ]
  }
  </script>

基本一般人が使うのはBreadcrumbList (パンくずリスト)とArticle (記事)ぐらいだと思います。
もうちょっと構造を複雑にしてみましょう。

  <script type="application/ld+json">
  {
    "@context": "https://schema.org",
    "@graph": [
      {
        "@type": "WebSite","@id": "サイトのurl#website",
        "url": "サイトのurl",
        "name": "サイトの名前",
        "description": "サイトの説明",
        "inLanguage": "ja-JP"
      },{
        "@type": "BreadcrumbList","@id": "#breadcrumb",
        "itemListElement": [
          {"@type": "ListItem", "position": 1, "name": "top", "item": "url"},
          {"@type": "ListItem", "position": 2, "name": "階層", "item": "url"},
          {"@type": "ListItem", "position": 3, "name": "現在", "item": "現url"},
        ]
      },{
        "@type": "WebPage","@id": "現ページurl#webpage",
        "url": "現ページurl",
        "name": "ページのタイトル",
        "description": "ページの説明",
        "isPartOf": { "@id": "サイトのurl#website" },
        "breadcrumb": { "@id": "#breadcrumb" },
        "about": {関連の情報},
        "mainEntity": {"@id": "現ページurl#main-categories"},
        "hasPart": [ { "@id": "現ページurl#submenu" }]
      },{
        "@type": "ItemList","@id": "現ページurl/#main-categories",
        "name": "攻略主要カテゴリ","description": "攻略主要カテゴリの説明",
        "itemListElement": [
          {"@type": "ListItem","position": 1,"name": "メインリンク1","url": "url"},
          ...略
          {"@type": "ListItem","position": 8,"name": "メインリンク8","url": "url"}
        ]
      },{
        "@type": "ItemList","@id": "現ページurl#submenu",
        "name": "サブ","description": "サブの説明",
        "itemListElement": [
          {"@type": "ListItem","position": 1,"name": "サブリンク1","url": "url"},
          ...略
          {"@type": "ListItem","position": 5,"name": "サブリンク5","url": "url"}
        ]
      }
    ]
  }
  </script>

・トップの指定。url#websiteは各ページ統一が必要

・isPartOfでどれに属するかを指定

・aboutで関連の情報を追加

・mainEntityをidで指定

・hasPartを使い同様にこのページ内に付属するコンテンツを指定

これくらい出来れば基本的には良いんじゃないかなと思います。

2026年4月17日金曜日

合わなかったゲームとかの話

ゲームを楽しむには素養が必要という話 

今回はプレイして個人的に合わなかったゲームのお話。
別にゲームが悪いのではなくで自分に適性がないなと思ったゲーム

Mortal Shell(モータル・シェル)

ソウルライクなゲームでレベルの概念はない。
ただし武器などの強化要素、シェルと言われる肉体強化などはありある程度緩和出来ている。
感想とか見ると硬化とかがあるのでソウル系より全然簡単だよみたいなレビューをみて丁度数百円で買えるほどのセールだったのでお試しで購入。

パリィの受付が本当に短くてだいぶ難しい。
数発で死ぬし回復手段が乏しい。
回避行動は○ボタン短押し、少しでも○ボタンが長いとダッシュになる。
この時点でなかなかの慣れが必要。
シェルを2つほど解放(最初のシェルを足すと3つ)して少し進めた時点で個人的に楽しむのが難しそうだなと。

パリィミスの硬直は滅茶苦茶長い。逆に回避の無敵時間は長め。
回避が強くなかったならそもそももっと序盤で諦めてたと思う。
3つのシェルになっても長剣一本で行動差もなくて、新鮮さも得られず一応倒しては死んでを繰り返せばある程度強化は出来るんだけどター獲得量が少なくて面倒さの方が高くなってしまった。

ソウルライク特有なのかは分からないけど全体的に説明がないので良く分からないが戦っている感じでモチベを上げれなかった。
そして最低限の目的地も分からず完全に迷子。

スタミナ制限が厳しくて2・3回攻撃+回避でほぼ使い切る。
それ以上攻撃するとスタミナが切れて剣すら振れなくなる。
これに関してはスタミナ制自体が個人的に向いてないのかもしれない。
パリィが1ミスが不利すぎるので1・2回攻撃→回避を延々と繰り返す事である程度は進めたけど他に本当にやる事がない。

今回は勝てなくてイライラというよりは単調過ぎて移動も戦闘も飽きてしまった面が大きい。
画面にほぼランドマークが無くて自分が何処に居るか分かり辛く、同じような画面が続くので飽きてしまう。
マップ表示なしにするなら、もうちょっとわかりやすいランドマークを配置して欲しかった。
本当に小さな段差も上がれない所も怠い。
ちょこっと降りた瞬間戻れないの悲しい。

死にゲーなのにロードが長い。
ソウルシリーズもそうなのか分からないけど、さっさと再開させて欲しい。
それとPS4だけど敵描画が遅く誰もいないと思って進んだら敵がふわぁと表示されるのもなんだかなぁと。

たぶん本当にソウルシリーズとか好きな人には面白いんじゃないかな。
L1+R1で必殺技みたいなのもあるし、硬化はワンエッセンスになってソウルライクに慣れてるなら楽しめそう。

2026年4月5日日曜日

htmlタグの構造

htmlの正しい構造について考える

今回はhtmlの正しい構造について説明します

<body>
<header>
<nav>
  <ul>
    <li>メニュー項目</li>
  </ul>
</nav>
</header>
<main>
<h1>記事のタイトル</h1>
<p>ここにはリード文が入ります。</p>
<section>
<h2>章のタイトル</h2>
<p>文章の段落。</p>
<h3>小見出し</h3>
</section>
<aside>
<p>補足情報など</p>
</aside>
</main>
<footer>
<p>&copy; サイト名</p>
</footer>
</body>

header「ヘッダー」

大抵のサイトでは上部に固定するメニュー部分と考えて良いです。
ここにH1を入れるという考えも一応ありますが、基本的にはページを跨ぐ不変的メニューエリアである場合が多いし、h1を混ぜるのは非推奨です。
H1をここに入れたらページ毎にヘッダー内に書き換えが発生するので面倒です。

また、古いサイトなどにあるロゴなどにh1を指定するような事は止めてください。
H1は後で説明しますがページ全体の主題なので正しくありません。

ヘッダーとかはそもそな話、htmlの構造としてありまりにもヘッダーメインフッターという構造だったため必要になってHTML5で実装されたものです。
そういう意味では昔は本当にシンプルな文章しか想定してなかったのが今はナビが必要になった結果ですね。

nav「ナビゲーション」

主にリンクを纏めるのに使いますがnavタグがありすぎてもダメなのでおおまかにはヘッダー配下にナビを置いてメインメニューの固まりとして使うのが大半だと思います

ul・li「リストタグ」

正直な所「ヘッダー>ナビ>リスト>リンク」という構造はほぼ固定です。
少しかっこよく言えばデファクトスタンダードです。

奇抜なデザインにしたいという願望が無い限りは安定でこの形です。
リストタグ自体は説明文系を挟まない端的な単語の列挙に使います。
ただ逆に言えばリンク群を配置するという時は単語列挙となり結果的にリストになります。

なのでそれが一番最初に使う位置としてはヘッダーナビリンクという感じこの上部で紹介。
構造としてはほぼほぼ定着しています。

リストかテーブルか?と悩んだ時はそれに補足する内容があるかで考えて下さい。
そして、補足や関連する内容が小さければテーブル、文章のような大きさならhタグ系になります。

main「メインコンテンツ」

ページ全体のメインとなる部分をこの部分に入れます。
ヘッダーにH1を入れた場合は

H1「主題」

ページ全体の何が書いてあるかという主題です。
idと違ってH1を複数使う事に対して絶対的な禁止とまではならないものの、事実上ページには1つだけ使ってください。
また、Hタグは階層的に1・2・3...と必ず階層構造が必要です。
H1から飛んでH3など飛んだりはしませんし、H1タグの上にH2タグを配置したりもしません。話の重要度とかの数値ではなくあくまでも文章構造による連番の階層構造です。

H1~H2の間「リード文」

Hが各構造のタイトルではあるが、H1の直下は実は基本的に内容を入れる所ではない。
本当に内容が1つしかなく章を分ける必要がない。またはツール等のでタイトルしかないような場合を除けば情報を表示し始めるはH2からというのが正しい構造。
その為、H1~H2の間はこのページではこういう内容について記述しますという端的な説明と目次を入れるの基本的な構造となります。

p「段落」

最初にpタグを入れるのがリード文の部分だと思うのでここで紹介。
1つの文章の区切りがpタグです。改行はbrを使ってください。ある程度長い文章の文節がこのpタグで区切るという感じです。

文章全般は全てpタグです。pタグが無くてもhtmlに文章は乗せれますが調整したくなった時にcssで調整できなくなるのでやめましょう。
ブログとかだと改行(br)しか存在してない場合もありますが、本来は文章の区切り区切りおきにpタグで区切りのが正しいです。
また、タグを直接見てる側としてはpで区切ってれば分の移動が楽。

section「セクション」

大きな章の区切りに使います。
大きな区切りであれば一応使ってよいという事にはなっていますが、基本的には直下にHタグがほぼ必須と言えます。
ただし、H1自体はページ全体を表すものなので通常sectionでは囲みません。
また、基本的な章の大きな区切りはH2であり、H3以降は細分化する内容となる為基本的な利用方法としては <section><h2></h2><h3></h3>...</section> という構造になります。
明らかに情報量が多いH3などがあれば別ですが基本的にはH2とセットという認識でOKです。

H2「章」

実際の内容を書くのはこのH2からという事になります。
主題のおおまかな内容をH2で区切り更に細かい分類がある場合はH3を使います。
ただし、区分されるものが簡潔で補足するような文章などが無い場合はリストタグを使ってください。

H3~H4「項・細目」

章を更に分割して説明が長くなる場合は分割します。
<section><h2></h2><h3></h3>...</section>
<section><h2></h2><h3></h3><h4></h4>...</section>
みたいな感じにセクション内で個々に深堀りする構造が基本です。

article「アーティクル=記事」

基本的には一旦使わないでので大丈夫です。
ブログやニュースや掲示板などサイト内で更に記事として独立する内容を入れる時に使います。
body内bodyみたいな気持ちです。1ページが独立してしまう記事などはbody直下をarticleで囲んで普通のhtmlみたいに書くと思って問題ないです。
先ずは基礎がないと使う事がないので一旦存在しているという程度に今は認識してください。

aside「アサイド=関連」

メインの文脈からは外れるが、関連性のある補足情報に使用します。
用語解説、関連記事へのリンク、サイドバーなどに使います。
あとは関連が薄いものとして広告などのエリアとしても使われるけどあれは補足じゃないしどうなんだろうか・・・と思っているものの、簡単に言えば隔離エリアとして許されている。

footer「フッター」

基本的には最低限入れるのはコピーライト。
あとはいわゆるフッターメニュー。大抵の場合サイト内循環を促すのに大量のメニューがある。

div「意味を持たないタグ」

divが過去にも説明しているが事実上のデザインタグ。無色透明の箱だと思って良い。
好きなサイズをつくり好きなようにサイズを変更し好きなように着色変更する。
タグで足りない要素全てdivとspanが担っている。

span「意味を持たないタグ」

インラインタグで改行されません。
つまり、文章などの装飾タグです。
インラインで行う足りないタグの全ての担っている。

<body> (ページ全体)
<header>
<nav> (ナビゲーション)
<ul> <li> (メニューのリスト)

※H1を入れるのは非推奨。共通メニューを置く場所。

<main> (メインコンテンツ)
<h1> (ページに1つだけの主題)
H1~H2の隙間 (リード文:内容の端的説明。必要なら+目次)
<section> (意味のある章の区切り)
<h2> (章のタイトル。ここから内容が始まる)
<p> (文章の段落。1つの意味のまとまり)
<h3> (さらに細かい項目の区切り)
<section> (意味のある章の区切り:このように複数でもよい)
<h2> (章のタイトル。ここから内容が始まる)
<p> (文章の段落。1つの意味のまとまり)
<h3> (さらに細かい項目の区切り)
<aside> (補足情報・サイドバー・広告など)
<footer> (コピーライトや補助メニュー)
</body>

2026年3月30日月曜日

コールバックって何?アロー関数って何?無名関数って何?

「コールバック」も「アロー関数」も「無名関数」も全部同じ関数でしかないという話

コールバックって何?アロー関数って何?無名関数って何?と思ってここに来たと思ます。

まず、所詮は全部関数です。
出来る事は全く同じで単に呼び方とか呼び出し方が違うだけ。

つまり、引数を渡してその結果を受け取る。
ぜーんぶ同じです。どれもfunctionです。

なので、じゃあ何が違うのかという話を今回は説明するだけ。
大前提としてまず普通のfunctionをどうやって使うのかを思いだす所から。

1.普通のfunction

function sample(n) {
  console.log(n);
}
sample(100);

だいたいこんな感じですよね。
『function 関数名(引数){処理}』
はい。合っています。

つまり、関数は特定の処理を何度も使うので独立させておいて、関数名を呼ぶことでその処理を引数を変えて何度も実行させます。
そういった場合に実は関数って呼んでるその機能って名前無くても成立しますよね?
関数の機能の部分って、『(引数){処理}』ここだけじゃないですか?

()「引数を渡す部分」』と『{処理}「実際に引数を使って処理する部分」
関数を関数たらしめる機能ってこれしかない

つまり、関数って実は『(){}』必要なのってこれだけだよねって言うのが全貌です。


関数=『(){}』このたった二つの括弧が関数って分かればもう「コールバック」も「アロー関数」も「無名関数」も9割理解出来たと思ってよいです。

1-2.関数は変数に代入出来る

もう一つ理解しておくべきことはこれです。
関数は変数にも代入出来る。
これは処理結果という話ではなくて、関数そのものを代入出来ます。
function abc(aaa){return aaa+1;}

という処理を作ります。
次にこの関数実行する場合

const a=abc(9);
console.log(a);//10

こうですね。『変数=関数()』
括弧を付けるとその関数が実行出来て、その結果が代入出来る。
次に関数を代入したい時は括弧を付けないで代入します。

const bbb = abc;
const b = bbb(9);
console.log(b);//10

関数本体を渡したいので引数などはいりません。
1つ手前で言った通り、括弧を付けると関数が実行されてしまう為です。
実際にはメモリの参照位置を渡してるんですが関数がそのまま代入されるって理解で一先ずOKです。
一旦理解したいのは関数は変数に代入出来るという事です。
ここまで理解できれば、無名関数もアロー関数も99%理解したと思ってよいです。

2.無名関数・アロー関数

無名関数とかアロー関数って他のサイトでも色々なサイトが説明してるけど分かり難い。
なぜなら、無名関数とかアロー関数の説明をしてるサイトって何処も
『const ccc = function(n) { console.log(n); };』
って、説明してるじゃないですか?
無名とか言ってるのに名前つけてるじゃん???? 『const ccc = function(n) { console.log(n); };』
ってするんだったら、そもそも
『function ccc(n) { console.log(n); };』
でいいよね????
なんか違うの????

さすが!天才!そこまで理解できれ完璧です。
そう、全く違いは無いです。

じつは、関数として処理内容が同じならどっちで書いても全く同じ処理です。
なので、基本的には

// 普通の関数

function ccc(n) { console.log(n); }

// 無名関数

const ccc = function(n) { console.log(n); };

// アロー関数

const ccc = (n) => { console.log(n); };

最初に説明したとおり、この三つ全部が関数の機能としては完全に全く同じです。
そうなんですよ。
名前を付けてしまえばどれも同じです。
この3つのパターンどれで定義しても実行方法も結果も同じです

じゃあなんで呼び方が違うのか????
はい。今回の話はそこです。

まず、名称に関してですが1つ前のセクションで説明した通り、関数は変数に代入出来ます。
前のセクションでは普通に定義した関数を別の名前で定義しなおしました
function abc(){処理}
const bbb=abc();

ですが無名関数はそもそも、名前付きの関数を定義していません。
const ccc=function(){処理}

はい。みたまんまです。「なまえを付けてない関数」を代入しています。
説明上必要だから一旦代入してるだけで無名関数っていうのがさしている部分は
『function(){処理}』
この部分です。
ここだけ見れば確かに関数名…つまり名前はない無名関数という名称には納得がいく。

でも・・・確かに名前は付いてないけど・・・それって名前がないと呼べなくね?
そう、その通り。

ついさっき説明した通り、何かに代入したらほぼほぼ普通の関数とかわりませんし、そうなったら利点も薄い。(巻き上げは後述)
つまり、名前無しで呼べるタイミングがあるって事です。
それがコールバックです!

3.「コールバック」も同じ関数である

さて、話の続きです。
関数という部分「(){}」は必要だけど、名前が無くても別にいいタイミングある。ってマ?って話でしたね。
実は、この名前を使わないで関数部分だけを処理する・・・これが実はコールバックなんですよ(大事なので二回目)。

簡単なものからいくと例えば、『forEach』とかですね。

array.forEach(コールバック文);

名前を書かないつまり、この「コールバック」ってかっこよく言ってるけどこれって実はただの関数の事なんですよ。
最初にも言ってる通り、「コールバック」も「アロー関数」も「無名関数」も全部同じ関数です。
関数という機能は同じです。つまり・・・

array.forEach(関数);

実際にはこれだけです。
初学者はコールバックが良く分からなくて詰まってしまう人が割と多いのですがただの関数と違いは無いんですよ。
なーのーで、必ずしもアロー関数を書く必要は全然ありません。
例えば、forEachなどは何処のサイトに行っても間違いなく

array.forEach((value, index) => {
  // 処理内容
});

って書いてあって、初学者はアロー関数の記述になじみが無いから一瞬でパンクして頭が「???」になるわけです。
ですが、先ほど言った通り、コールバックっていうのはただの関数なので普通の関数でも良いんですよ。
つまり、一旦このコールバックって言うところに普通に関数を記述してみれば初学者も理解しやすい・・・と思うのにどのサイトもアロー構文しかないんですよね。
「コールバックってアロー構文じゃなくてもかけるの?????」
当然問題ありません。
無名関数とかアロー関数っていうのは元々の関数を記述際に別に名前いらないよね?っていう関数の進化でしかないので別に関数を普通に記述しても問題ないです。
という訳で、forEach文を普通に名前付き関数で書くと・・・

// 2. forEachの引数の中で、そのまま「function 名前()」を定義する
const ar = [1, 2, 3];            
ar.forEach(
  function eee(v) {
    console.log(v);
  }
);

見ての通りこの様に記述出来ます。一般的な普通の関数です。
『function eee(v) {console.log(v);}』
関数eee(引数){処理}これだけ。
今回最初に書いた普通の関数と同じです。引数を取得してそれをそのまま表示するだけ。
この時に、第一引数として取得出来るのが配列の中身です。
なーのーでこの「v」には配列が順番に渡されるので1・2・3と表示されます。

たったそれだけです。
mapとかfilterとか他にもコールバックっが使えるメソッドがありますが。
引数にその中身が連続で渡されるだけです。

これでまた、話が最初に戻ります。
「コールバック」も「アロー関数」も「無名関数」も全部同じ関数
なーのーでー・・・次に無名関数にしてみましょう。 だって、ここで必要なのって引数を受け取る『 () 』この括弧と処理を入力する『 {} 』ここしか必要ないじゃないですか?

// 1. 普通の関数を無名関数にする=関数名が無くなるだけ
const ar = [1, 2, 3];            
ar.forEach(
  function(v) {
    console.log(v);
  }
);

勿論これでも動きます。
関数名があろうがなかろうが処理に必要なのは『(){}』これだけですもんね。
名前が無くなった所で処理に必要なものは足りています。

そしてここで更に「function」って記述いらないよね・・・?ってなって出来たのがアロー関数です。
アローで必要なのは『 () 』と『 {} 』それとそれをつなぐアロー『 => 』だけです。

// 3. 無名関数をアロー関数にする
const ar = [1, 2, 3];            
ar.forEach(
  (v) => {
    console.log(v);
  }
);

はい。全く同じ処理がこれだけ短くなりました。
殆ど関数としての原型が無い・・・。
そう、初学者はこれだけで良く分からなくなっちゃう。
なので関数って実質『(){}』たったこれだけなんだぁって理解出来ればOK!

ここまできたらもう一押し理解しましょう。
javascriptを作ってきた人たちはもっと概念的理解にたどり着きます

関数が「(){}」だけでいいなら・・・『引数』『処理結果』だけあればそもそも『 () 』も『 {} 』も要ら居ないんじゃない?
つまり・・・

// 3. 更に省略したアロー関数
const ar = [1, 2, 3];            
ar.forEach(v => console.log(v));

使用頻度が高い引数が1つで処理が1つ(returnが1つ)だけならこれでいいよね?
っていうのがjavascriptのアロー関数って事です。
初学者がこれを関数だと理解出来ないのはもうしょうがないと思います。
もう概念なんですよ。『引数と結果』っていうこういう処理概念です。

とは言え、コールバックっていうのが関数だという所だけ分かっていれば理解も出来るし、慣れます。
そして、慣れると無駄な文字を書かなくて良いのでやはり利便性が勝ります。

最後に、でも複雑な処理がコールバック部分に入ったら見辛いのでは・・・?
はい。見辛いです。
ですが、コールバック部分に入れるのが関数つまりは関数を代入すれば自動でそこに引数を渡してくれるんです。 つまり

// コールバック部分に関数を直接代入
function eee(v){ console.log(v) };
const arr = [1, 2, 3];
arr.forEach(eee);

このように記述する事も出来ます。
特に多いパターンはDOMのイベントリスナーとかは処理が大きくなったらこの様に関数を分離してコールバックで関数を呼ぶというパターンも増えます。
ちなみに、このイベントリスナーとかで関数に間違えて括弧を付けてしまい関数が実行されるっていうのが良くある話なので「何を代入したいか」というのを忘れずに。

4.唯一の大きな違い「巻き上げ」と「再代入」

「機能は全部同じ」と言いましたが、JavaScriptの挙動として一つだけ決定的な違いがあります。
それは、「いつ呼び出せるか」「上書きできるか」というルールです。

① 巻き上げ(Hoisting)

普通の function で宣言した関数は、コードのどこに書いても「一番上にあるもの」として扱われます。
つまり、定義する前に行をまたいで呼び出すことができます。

test(); // エラーにならない!実行できる

function test() {
  console.log("動くよ");
}

対して、変数に代入する「無名関数」や「アロー関数」は、代入する前に呼ぶとエラーになります。
変数は宣言されるまで存在しない扱いだからです。

② 再代入の禁止(constによる保護)

普通の function は、後から同じ名前で関数を作ると上書きされてしまいます。
しかし、const を使ってアロー関数を定義すれば、間違えて同じ名前の関数を作ろうとした時にエラーで教えてくれます。

const myFunc = () => { console.log("絶対守るマン") };

// 同じ名前で作り直そうとするとエラーが出る(安全!)
const myFunc = () => { ... }; 

③暗黙return

軽く触れたけれどアロー関数はとにかく短く記述する事が目的に出来ている。
なので『引数』『結果』が最短記述出来る様に出来ておりreturnが1つだけの場合、暗黙的に結果をreturnしてくれる
『v=>v+1』とした場合、これの実行結果はvが引数として処理されv+1が自動的にreturnで返って来る。
これら「暗黙return」と「 {} 不要」の必要条件は、式が1つである事。
もっと簡単い言えば、ブロックが1つである事。更に言えば「 ; 」が無い事です。
そのため式が一つであった場合でも「 ; 」が付くと暗黙returnと括弧なしが利用出来ません。
最短記述をしたい場合は「 ; 」は消す必要があります。

また、引数側は引数が一つの時のみ「 () 」が省略できます。
引数が複数ある場合『 (a,b)=>a+b 』みたいにする必要があります。

④アロー関数はthisを拘束しない(Lexical this)

アロー関数の最大の武器は、「自分自身の this を持たない」という性質です。
JavaScriptの this とは、簡単に言えば「その処理を動かしている実行主(オーナー)」を指します。しかし、従来の function で書かれた関数(無名関数含む)は、呼び出し方によってこの this がコロコロと変わってしまう「浮気性」な性質がありました。

アロー関数はこの問題を解決し、「関数が定義された場所の this を一生使い続ける」という固定の挙動をします。

【無名関数として使う場合の違い】

イベントリスナーや setTimeout などで「使い捨ての関数(無名関数)」を渡す際、その差が顕著に出ます。
従来の無名関数: 実行時に this が「ボタン要素」や「Window」に勝手に書き換わります。
アロー関数の無名関数: 外側のクラスやオブジェクトの this をそのまま保持します。
これにより、const self = this; といった「thisの退避」という古いテクニックが不要になりました。

【メリットとデメリット】

メリット デメリット(注意点)
this の混乱がなくなり、コードが直感的になる。 オブジェクトのメソッドとして使うと、そのオブジェクト自身を this で参照できない。
記述が短くなり、コールバック関数がスッキリ書ける。 arguments(引数の集合)や new(コンストラクタ)が使えない。


「その場限りの処理(コールバック)」や「外側の this を使いたい時」はアロー関数。「オブジェクトのメソッド」や「this を動的に切り替えたい時」は function、という使い分けが現代のスタンダードです。

まとめると、「どこでも呼べる自由な functionか、「ルールが厳格で安全な const + アロー関数か、という使い分けになります。
最近の開発でアロー関数が好まれるのは、この「勝手に書き換わらない安全さ」があるからでもあります。

2026年3月20日金曜日

svgを動的に生成してみた話

ドット絵SVGを動的生成

今回はsvgを小さくデータで持ちたいなっていう超局地的な内容です。

HTMLに直接埋め込む

svgファイルはテキストデータで作る画像なので、以下のように直接htmlに埋め込む事も可能です。

<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" shape-rendering="crispEdges">
  <!-- 画像の座標情報 -->
</svg>

また、cssに直接書いて参照させる事も可能です。

javascript化

今回のコードは以下の通り。

<script>
    (function renderGolemIcon() {
        const container = document.getElementById('golem-icon-container');
        if (!container) return;

        // カラーパレット
        const colors = {
            "#ffa500": 0,
            "#8b4513": 1,
            "#808080": 2,
            "#000000": 3,
            "#ffff00": 4
        };
        const colorList = ["#ffa500", "#8b4513", "#808080", "#000000", "#ffff00"];

        // SVGから1pxずつ抽出した完全なデータ
        const dots = [
            [7,0,0],[8,0,0],[9,0,0],[10,0,1],[11,0,0],
            [7,1,0],[8,1,0],[9,1,0],[10,1,0],[11,1,1],[12,1,0],
            [6,2,0],[7,2,0],[8,2,0],[9,2,0],[10,2,1],[11,2,0],[12,2,1],
            [3,3,2],[6,3,0],[7,3,0],[8,3,0],[9,3,1],[10,3,0],[11,3,1],[12,3,0],
            [3,4,2],[4,4,2],[6,4,0],[7,4,0],[8,4,1],[9,4,0],[10,4,1],[11,4,1],[12,4,1],[13,4,0],[15,4,2],
            [4,5,2],[5,5,0],[6,5,0],[7,5,1],[8,5,0],[9,5,1],[10,5,0],[11,5,1],[12,5,1],[13,5,1],[15,5,2],
            [3,6,2],[4,6,0],[5,6,0],[6,6,0],[7,6,0],[8,6,0],[9,6,0],[10,6,0],[11,6,1],[12,6,1],[13,6,2],[14,6,2],[15,6,2],
            [2,7,2],[3,7,2],[4,7,0],[5,7,1],[6,7,3],[7,7,3],[8,7,3],[9,7,3],[10,7,0],[11,7,0],[12,7,2],[13,7,2],[14,7,2],[15,7,2],
            [2,8,2],[3,8,2],[4,8,2],[5,8,3],[6,8,4],[7,8,3],[8,8,3],[9,8,4],[10,8,3],[11,8,3],[12,8,2],[13,8,2],[14,8,2],
            [3,9,2],[4,9,0],[5,9,1],[6,9,4],[7,9,3],[8,9,3],[9,9,4],[10,9,3],[11,9,3],[12,9,0],[13,9,1],[14,9,0],
            [4,10,0],[5,10,0],[6,10,3],[7,10,3],[8,10,3],[9,10,3],[10,10,3],[11,10,0],[12,10,1],[13,10,0],[14,10,1],[15,10,0],
            [1,11,0],[2,11,0],[3,11,0],[4,11,1],[5,11,0],[6,11,0],[7,11,0],[8,11,0],[9,11,0],[10,11,0],[11,11,1],[12,11,1],[13,11,0],[14,11,1],[15,11,0],
            [0,12,0],[1,12,0],[2,12,0],[3,12,1],[4,12,1],[5,12,1],[6,12,0],[7,12,1],[8,12,1],[9,12,1],[10,12,1],[11,12,1],[12,12,1],[13,12,1],[14,12,0],[15,12,1],
            [0,13,0],[1,13,0],[2,13,1],[3,13,1],[4,13,1],[5,13,0],[6,13,0],[7,13,0],[8,13,1],[9,13,1],[10,13,1],[11,13,1],[12,13,0],[13,13,1],[14,13,0],[15,13,0],
            [0,14,0],[1,14,1],[2,14,1],[3,14,0],[4,14,0],[5,14,0],[6,14,0],[7,14,0],[8,14,0],[9,14,0],[10,14,0],[11,14,0],[12,14,0],[13,14,1],[14,14,1],[15,14,0],
            [0,15,0],[1,15,1],[2,15,1],[3,15,0],[4,15,0],[5,15,0],[6,15,0],[7,15,0],[8,15,0],[9,15,0],[10,15,0],[11,15,0],[12,15,0],[13,15,0],[14,15,1],[15,15,1]
        ];

        let rectsHtml = '';
        dots.forEach(([x, y, colorIdx]) => {
            rectsHtml += `<rect x="${x}" y="${y}" width="1" height="1" fill="${colorList[colorIdx]}" />`;
        });

        container.innerHTML = `
            <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" shape-rendering="crispEdges">
                ${rectsHtml}
            </svg>
        `;
    })();
</script>

実際に描画されたSVG

ちなみに、この通り実際に復元可能です。
仕組み的には前に作ったsvgドット絵エディタで作ったsvgのデータをforを回して復元するだけです。なのでwidthもheightも1固定。
カラーパレットは配列化してindex値で取り出し。
16x16ですが、空白の位置もあるので配列横軸は16個ない場所もあります。
逆に縦軸は全部色があるので16個あります。

関数化してみる

もう一度使うかと言われると使わないかもしれないけど関数化してみるテスト。
idは唯一キーなのでidだと1か所にしか復元できないものの一旦はこれで良いかな。
そして、もう一度と言ったものの…ここまで作ったけど結局使わなかったっていう・・・。
でもまぁパレット値を弄るだけで全体の指定色を変えれるので使う機会はあるのかもしれない。

<script type="module">
    /**
     * ピクセルアイコンを描画する汎用関数
     * @param {string} id - 描画先の要素ID
     * @param {Array} pixels - [x, y, colorIdx] の配列
     * @param {Array} colors - カラーコードの配列
     */
    function renderPixelIcon(id, pixels, colors) {
        const container = document.getElementById(id);
        if (!container) return;

        let rectsHtml = '';
        pixels.forEach(([x, y, colorIdx]) => {
            const fill = colors[colorIdx] || '#000';
            rectsHtml += `<rect x="${x}" y="${y}" width="1" height="1" fill="${fill}" />`;
        });

        container.innerHTML = `
            <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" shape-rendering="crispEdges">
                ${rectsHtml}
            </svg>
        `;
    }

    // 初回実行処理
    const init = () => {
        // ゴーレムのカラーパレット
        const golemColors = ["#ffa500", "#8b4513", "#808080", "#000000", "#ffff00"];

        // ゴーレムのドットデータ (All dots included)
        const golemPixels = [
            [7,0,0],[8,0,0],[9,0,0],[10,0,1],[11,0,0],
            [7,1,0],[8,1,0],[9,1,0],[10,1,0],[11,1,1],[12,1,0],
            [6,2,0],[7,2,0],[8,2,0],[9,2,0],[10,2,1],[11,2,0],[12,2,1],
            [3,3,2],[6,3,0],[7,3,0],[8,3,0],[9,3,1],[10,3,0],[11,3,1],[12,3,0],
            [3,4,2],[4,4,2],[6,4,0],[7,4,0],[8,4,1],[9,4,0],[10,4,1],[11,4,1],[12,4,1],[13,4,0],[15,4,2],
            [4,5,2],[5,5,0],[6,5,0],[7,5,1],[8,5,0],[9,5,1],[10,5,0],[11,5,1],[12,5,1],[13,5,1],[15,5,2],
            [3,6,2],[4,6,0],[5,6,0],[6,6,0],[7,6,0],[8,6,0],[9,6,0],[10,6,0],[11,6,1],[12,6,1],[13,6,2],[14,6,2],[15,6,2],
            [2,7,2],[3,7,2],[4,7,0],[5,7,1],[6,7,3],[7,7,3],[8,7,3],[9,7,3],[10,7,0],[11,7,0],[12,7,2],[13,7,2],[14,7,2],[15,7,2],
            [2,8,2],[3,8,2],[4,8,2],[5,8,3],[6,8,4],[7,8,3],[8,8,3],[9,8,4],[10,8,3],[11,8,3],[12,8,2],[13,8,2],[14,8,2],
            [3,9,2],[4,9,0],[5,9,1],[6,9,4],[7,9,3],[8,9,3],[9,9,4],[10,9,3],[11,9,3],[12,9,0],[13,9,1],[14,9,0],
            [4,10,0],[5,10,0],[6,10,3],[7,10,3],[8,10,3],[9,10,3],[10,10,3],[11,10,0],[12,10,1],[13,10,0],[14,10,1],[15,10,0],
            [1,11,0],[2,11,0],[3,11,0],[4,11,1],[5,11,0],[6,11,0],[7,11,0],[8,11,0],[9,11,0],[10,11,0],[11,11,1],[12,11,1],[13,11,0],[14,11,1],[15,11,0],
            [0,12,0],[1,12,0],[2,12,0],[3,12,1],[4,12,1],[5,12,1],[6,12,0],[7,12,1],[8,12,1],[9,12,1],[10,12,1],[11,12,1],[12,12,1],[13,12,1],[14,12,0],[15,12,1],
            [0,13,0],[1,13,0],[2,13,1],[3,13,1],[4,13,1],[5,13,0],[6,13,0],[7,13,0],[8,13,1],[9,13,1],[10,13,1],[11,13,1],[12,13,0],[13,13,1],[14,13,0],[15,13,0],
            [0,14,0],[1,14,1],[2,14,1],[3,14,0],[4,14,0],[5,14,0],[6,14,0],[7,14,0],[8,14,0],[9,14,0],[10,14,0],[11,14,0],[12,14,0],[13,14,1],[14,14,1],[15,14,0],
            [0,15,0],[1,15,1],[2,15,1],[3,15,0],[4,15,0],[5,15,0],[6,15,0],[7,15,0],[8,15,0],[9,15,0],[10,15,0],[11,15,0],[12,15,0],[13,15,0],[14,15,1],[15,15,1]
        ];

        // アイコンを描画
        renderPixelIcon('golem-icon-container', golemPixels, golemColors);
    };

    // 実行
    init();
</script>

最後に

技術的に面白いかとやってみましたが、根本的にはそもそも画像と同様に使えるのでsvgファイルとしてimgで参照させましょう。
そうすればcssも汚されないし、htmlも汚れません。

2026年2月16日月曜日

スマホだけで改行する時どうするか

 今回は改行の話

スマホのみ改行はbrかspanかdivか

まず、改行がなんのために必要かという当たり前の話としては人が文章を読みやすくするためです。
じゃあ改行されるような要素にどんな意味があるのかというところからですが・・・

コンテンツ部分が記事となる文章であれば<article>
その中に記事としての区切りがあれば<section>
ある程度の文章の区切りは<p>
文節分ける時が改行の<br>
文章の装飾、インラインは<span>
デザイン的区切り、ブロック単位の装飾は<div>

スペースを制御するのに<br>を使うのは意味タグとして正しくありません。
ですが、逆に言えば改行として問題ないならば<br class="br-md">とかのほうが正しい。

今回の話はTableのセルの中身

今回記事を書く元になった問題はセルの中身。
幅100%でスマホになると見辛い。
項目として1つ~3つの文字アイテムがある時、2・3の文字列がごちゃる。
安直な解決策は面倒臭いなら
「あああああ」、
「いいいいい」、
「ううううう」
こうで良い。PCでもスマホでも大きな問題はない。
ただ、PCで見た時に無駄に縦に伸びる。
PCならば「あああああ」、「いいいいい」、「ううううう」となって欲しい。
もう一つ簡単な方法はTableを囲んでoverflow。

単純な区分けとしてはデザインか否か

今回の場合は列として複数あるが一つのデータであり、改行で問題ない。
であれば、brにclassで良い。なぜなら制御したいのは改行だけだから。
spanで囲むのと違いbrなら明確に改行を制御しているのが分かる。
装飾が目的ならspan、またデータが複数多い場合はリストが正しい。

まぁリストを含むほどのTableになるのであればたぶん列か行に分散されるような気はする。
また、divで囲むブロックとしての情報ならやはり行を増やす様なデータな気がする。

例えば装飾するならば改行不要のデータにもspanで囲む必要性がある場合、でも今回の場合は1つのデータしかない場合spanで囲まないし囲む必要も特にない。
もしここに装飾が本当に必要になったならその時にspanで囲めばいい。
だから今回はbrという感じ。

装飾方法

記述的には不要な定義を入れない事を考えれば片方だけの方が良い。
デフォルトが改行そのまま、PCの時だけ挙動を変更してnoneにする方が良い。

@media (min-width: 768px) {.br-md {display: none;}}
ちなみにTailwindならbr hidden md:inline または、 br md:hidden(逆パターン)と簡単に設定できる。

2026年2月2日月曜日

CRYMACHINA:クライマキナで原始疑似完全数の式を学んだ話

原始疑似完全数の式のお話

クライマキナというゲームには5桁のアドレスを入力することで入れるエリアがある。
メインストーリーとは関係ないため、クリア後に行う事になった。

入力アドレスはそれぞれ規則性があり総当たりする必要はない。
今回はそのうちの一つの条件にあった原始疑似完全数のお話です。

ちなみに今から書くことはアドレス解析ページ(クライマキナ完全アドレス一覧)で既に書いたことなので目新しい内容は無いです。

約数とは?

約数とは? ある整数を割り切ることができる(割った余りが0になる)整数のことです。 例えば「6」なら, 1, 2, 3, 6 で割り切れるので, これらが約数です。

完全数とは?

完全数は「その数自身を除く約数をすべて足すと、元の数と等しくなる数」です。

完全数6の場合
「6÷1、6÷2、6÷3、6÷6」これら全て余りが0。つまりこれらが約数。
約数=「1, 2, 3, 6」正し自身の数を含めないので利用数約数は「1, 2, 3」です。
この出てきた数を全て足すと「1+2+3=6」となります。
この様に数値の約数を全て足すと元の数字になるものを完全数と言います。

約数 結果
6 1, 2, 3 1 + 2 + 3 = 6 完全数
28 1, 2, 4, 7, 14 1 + 2 + 4 + 7 + 14 = 28 完全数
496 1, 2, 4, 8, 16, 31, 62, 124, 248 1 + 2 + 4 + 8 + 16 + 31 + 62 + 124 + 248 = 496 完全数

疑似完全数とは?

次に、疑似完全数についてです。 完全数の条件を少しだけ「ゆるく」したのがこれです。

完全数は、自分以外の約数を「全部」足さなければなりませんでした。対して疑似完全数は、「自分以外の約数の中から、いくつか(一部でも全部でも可)を選んで足したとき、元の数と等しくなる数」を指します。

12
12の約数:1, 2, 3, 4, 6, 12

自分以外を全部足すと 1+2+3+4+6 = 16 となり、12を超えてしまいます。

しかし、ここから 2, 4, 6 だけを選んで足すと、合計は 12 になります。
このように「約数から好きな数字を選んで足し算して元の数が再現できる」のが疑似完全数です。

原始疑似完全数とは?

本題前の本題です(混乱)。
疑似完全数の中には、少し「ズルい」やつがいます。例えば「6」が完全数(=疑似完全数)だと分かれば、その倍数の「12」や「18」も、約数の中に「6を作るセット」を自動的に持ってしまうため、当然のように疑似完全数になります。

これでは面白くない、ということで定義されたのが原始疑似完全数です。

原始疑似完全数とは、「疑似完全数であり、かつ、その約数の中に疑似完全数を一つも持たない数」のことです。
つまり、「他の疑似完全数の力を借りずに、自力で初めて疑似完全数になった最小単位の数」と言い換えられます。

  • 6 は原始疑似完全数です(約数 1, 2, 3 の中に疑似完全数がないから)。
  • 20 も原始疑似完全数です(約数 1, 2, 4, 5, 10 の中に、一部を足して自分になる数は 20 以外にありません)。
  • 12 は疑似完全数ですが、原始ではありません。なぜなら、約数の中に 6(疑似完全数)が含まれているからです。

n∈PPS⇔n pseudoperfect ∧∀d|n (1<d<n⇒d∉PP)

さて、完全な本題である原始疑似完全数の数式です。これが既に読める人はここで解散してください。今回はこれを説明するために記事を作っただけです。
まぁ一般人がゲームやる為にこんな記号見せられても分かるはずもないだろうというのが正直なところだと思います。順番に行きましょう。

n∈PPS⇔

・「n」は指定した数字
・「∈」は同じって事です。正確にはそれに含まれるという意味。
・「PPS」は原始疑似完全数

つまりnが原始疑似完全数に含まれる。という説明です。まぁ言葉で読む分には「n=原始疑似完全数」こういう事です。

・「⇔」これの左右が同じ事を表します。
つまり「n=原始疑似完全数」⇔(原始疑似完全数の条件)
nが原始疑似完全数になる条件は=「n pseudoperfect ∧∀d|n (1<d<n⇒d∉PP)」
こういう事です。という事は「⇔」の右側が読み解ければ原始疑似完全数が何なのかわかるって事です。

n∈PPS⇔n pseudoperfect∧

・「n pseudoperfect」はnとして使う値は疑似完全数
つまり「原始疑似完全数=疑似完全数」

これは事前に説明してる通り、疑似完全数というカテゴリの中に原始疑似完全数が存在する為です。

・「∧」はandです。なおかつって事ですね。
原始疑似完全数=nが疑似完全数かつ(原始疑似完全数の条件)
これによって確認すべき条件がより右にスライドしました。

∀d|n (1<d<n⇒d∉PP)

やっと事実上の条件の肝となる部分に到達しました。
・「∀」はforAll、全てのという意味
・「d|n」はdでnを割り切る=「n÷dの余りが0」
・「∀d|n」
こうなった場合はnに総当たりで1~nの間で割り算するって事ですね。条件が割り切る=余りが0になる=約数が取得出来るという事です。
nを割り切れた値が全て=約数群d

d = [a for a in range(1, n + 1) if n % a == 0]

約数一覧がGET出来たので約数が何だったら原始疑似完全数なのかという話になります。という事は
原始疑似完全数=nが疑似完全数かつnの約数が…(原始疑似完全数の条件)
ここまで来ました。

∀d|n (1<d<n

この先の条件はただの不等号です。
・「1<d<n」dが1より大きく、nより小さい
「1<d」なのは約数1はどの数値であっても割り切れるため条件から除外される。
「d<n」は自分より小さいものだけを対象とする

これを全てのdに対して行うで

d = [a for a in range(2, n) if n % a == 0]

1を除外し、自身も含めない。

(1<d<n⇒d∉PP)

・「⇒」もしそうだったら
・「d∉PP」d∉PP. dが疑似完全数ではない。
つまり「約数群全てが過去に出た疑似完全数を含むことがない」って事ですね

n∈PPS⇔n pseudoperfect ∧∀d|n (1<d<n⇒d∉PP)

最後に全部を通しで見てみましょう
「原始疑似完全数はnが疑似完全数かつnの約数全てが自身より小さい疑似完全数を含まない」

これでやっと式の内容が全て解読できましたね。お疲れ様でしたー。

追記「1<」は無くていい。
n PP∧∀d|n (d<n⇒d∉PP)
後から見たらそもそもnは疑似完全数という前提なんだから1が含まれていない。 つまり、1より大きいと書く必要はなくて単純に約数dがnより小さければOKですね。