1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

なぜsort()で全部変わる?参照・アドレス・コピーをまとめて理解!

Posted at

今回解いたのは配列の最大値と最小値を出すだけの問題。

JavaScriptで配列を扱っていて、sort()を使ったら他の変数の中身まで変わってしまった…。その理由は、「参照」と「メモリのアドレス」にあった!


問題概要

N 個の整数が与えられるので、最大の数と最小の数を半角スペース区切りで出力せよ。

N 個の整数を大きい順や小さい順に並び替える操作を考えて解いてみよう。


入力例:

5
1 3 5 2 4

出力例:

5 1



📌Math.maxメソッドを使う 

const rl = require('readline').createInterface({input:process.stdin});
const lines = [];

rl.on('line',(input)=>{
    lines.push(input);
});

rl.on('close',()=>{
    const N = Number(lines[0]);
    const nums = lines[1].split(' ').map(Number);
    
    const Max = Math.max(...nums);
    const Min = Math.min(...nums);
    
    console.log(Max, Min)
    
});

...nums で配列の中身を個別の値に展開して渡す。


📌sort()を使ったバージョン

N 個の整数を大きい順や小さい順に並び替える操作を考えて解いてようとのことだったので、考えてみた!

NG例:

const N = Number(lines[0]);
const nums = lines[1].split(' ').map(Number);
    
const asc = nums.sort((a,b) => a - b);
const desc = nums.sort((a,b) => b - a);

console.log(desc[0], asc[0]); 両方降順になる

なぜか両方とも [5, 4, 3, 2, 1] に!?!?!?



メモリと参照:sort()が他の変数にも影響する理由とは?

🔍 メモリとアドレスって何?

JavaScriptでは、配列やオブジェクトなどの複雑なデータは「値」ではなく「アドレス(場所)」を変数が保持する。

たとえば、次のように配列を作成したとする。

let nums = [3, 1, 2];

このとき、配列そのものはメモリ上のどこか(例: 0x1234)に保存される。

そして、変数 nums はその「場所(アドレス)」を覚えているだけ。


🧠 図解①:配列の作成

メモリ:
アドレス 0x1234: [3, 1, 2]

変数:
nums → 0x1234(配列 [3, 1, 2] を指す)



🧪 asc にコピーしてみる

let asc = nums;

これで ascnums と同じアドレス(0x1234)を参照。


🧠 図解②:参照のコピー

メモリ:
アドレス 0x1234: [3, 1, 2]

変数:
nums → 0x1234  
asc  → 0x1234

ここが重要! → ascnums は同じデータを見ている!


🔁 sort()をするとどうなる?

nums.sort((a, b) => a - b); // 昇順 → [1, 2, 3]

この時、配列の中身自体(アドレス 0x1234 の内容)が書き換えられる。


🧠 図解③:sort()の影響

メモリ:
アドレス 0x1234: [1, 2, 3]

変数:
nums → 0x1234  
asc  → 0x1234  ←中身が変わってる!

つまり asc の中身も一緒に変わってしまう。

😱 別の変数でもっと混乱!

let desc = nums.sort((a, b) => b - a); // 降順 → [3, 2, 1]

この sort() も同じアドレスを操作しているため…



🧠 図解④:すべて同じ配列に

メモリ:
アドレス 0x1234: [3, 2, 1]

変数:
nums → 0x1234  
asc  → 0x1234  
desc → 0x1234

結果:nums, asc, desc は全部同じデータになってしまう!


✅ 対策:スプレッド構文でコピーを作ろう!

let asc = [...nums].sort((a, b) => a - b);   // 昇順コピー
let desc = [...nums].sort((a, b) => b - a);  // 降順コピー

これで nums の元データは変わらず、ascdesc は別のアドレスを持つ独立した配列になる!


💡 ポイントまとめ

  • sort() で他の変数も変わる → 同じ配列(アドレス)を共有しているから
  • let b = a でコピーにならない → 値ではなく参照(アドレス)がコピーされる
  • スプレッド構文 [...a].toSorted() で配列のコピーを作る



✅OKコード完成例:

const rl = require('readline').createInterface({ input: process.stdin });
const lines = [];

rl.on('line', (input) => {
    lines.push(input);
});

rl.on('close', () => {
    const N = Number(lines[0]);
    const nums = lines[1].split(' ').map(Number);


    // 昇順ソート(最小値)
    const asc = [...nums].sort((a, b) => a - b);   

    // 降順ソート(最大値)
    const desc = [...nums].sort((a, b) => b - a);  


    console.log(desc[0], asc[0]);
});

まとめ:

  • Math.max(nums)NaN を返すので、Math.max(…nums) で展開する
  • sort() は破壊的 → コピーしてから使おう!
  • スプレッド構文や .toSorted() を使う。
  • 配列は参照型で、変数は配列の『アドレス』を指す

配列を扱うときは、「コピーするかどうか」を意識するのが大事ってことを学んだ!




僕の失敗談(´;ω;`)と解決法🐈

1
0
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?