なぜ学校はリストよりも配列を教えるのですか?[閉まっている]


36

私の学校での最初のプログラミングクラスの割り当てのほとんどでは、配列を使用する必要がありました。私は今フルタイムで働いており、私が取り組んだプロジェクトでアレイを使用したことはありません。既存のプロジェクトでさえ、どこでも配列の使用を見たことはありません。私の意見では、リストは使いやすく標準です。教授が課題でアレイを使用するよう生徒に指示するのはなぜですか?学生が基本を理解するためだけですか?

ほとんどの大学がJavaを教えているため、この質問はJavaに固有のものです。


7
配列はより基本的です。
user253751

コメントは詳細なディスカッション用ではありません。この会話はチャットに移動さました
世界エンジニア

回答:


120

配列はインデックス付けや境界などの概念を教えるため、コンピュータープログラミングの2つの基本的に重要な概念です。

リストは「標準」ではありません。配列が完全に適合するさまざまな問題空間があります。


コメントは詳細なディスカッション用ではありません。この会話はチャットに移動さました
ワールドエンジニア

48

彼らはおそらく、コンピューターがどのように機能するかを最も正確に表すデータ構造から始めたいと考えていたので、操作しやすくするリストのような高レベルの抽象化を導入し始める前に、基礎に精通しています。そうしないと、特定の構造またはアルゴリズムが一部の操作では低速/高速であり、他の操作では高速ではない理由を理解する方法がありません。リンクされたリストから実際にコンピューターのメモリが作成された場合、世界はまったく異なる場所になります。

同じ理由で、大学での最初のプログラミングクラスはCで、残りのクラスはすべてC ++、Java、その他の言語でした。Cが何らかの形で優れていたり簡単であったりするのではなく、C(および配列)が何も隠さないということです。


7
リストは実際のコードでの作業が簡単ですが、配列は基本的かつ普遍的であるため(Javaの)リストはそうではありませんが、配列は(完全に)理解しやすく、理解することが重要です。少なくともそれは私の意見です。
Ixrec

21
配列にデータを保存して後でアクセスする割り当ては、データ構造の割り当てです。気付いていないかもしれません。優れたエンジニアを生み出しているのは何なのか、基本的な計算モデルを理解しているのか、それとも言語の標準ライブラリを学習しているのかを自問する必要がありますか?一般的なコンセンサス(そして、私は同意します、fwiw)は、最初に計算の基本を理解しなければ、ライブラリの内容の多くを理解しないということです。
ケントA.

12
LinkedList、ArrayList、OrderedListなど。最初にどのリストを学習する必要がありますか?そもそもなぜそれらが存在するのか理解していないなら、彼らがあなたのために何をしてくれるのか、どう思いますか?
ケントA.

10
@KentAndersonへの+1。学校は、データ構造を低レベルで理解するエンジニアを育成する必要があります。理想的には、Cで基本構造を簡単に実装できるエンジニアを作成します。他のプログラムはすべてJavaSchoolです。
クリスチャンウィルマン

2
「おそらく、コンピューターの動作を最も正確に表すデータ構造から始めたいと考えていました」–では、リスト構造またはオブジェクト構造のメモリーを備えたコンピューターについてはどうでしょうか。「Cが何らかの形で優れていたり簡単であったりするのではなく、C(および配列)があなたから何も隠さないということです。」–お使いのコンピューターにAS / 400などのポインターがない場合を除きます。AS/ 400では、Cは基本的にVMで実行され、ほとんどすべてを隠します。
ヨルグWミットタグ

21

上記の答えは素晴らしいですが、私は別のことを考えています。Javaのmain()方法では、学生は基本的な配列に非常に早く、多くの場合は授業の初日とすぐに遭遇します。どうして?

public static void main(String[] args)

Hello Worldを書くために最初に対処しなければならないことは、それ以降です。(最初にBlueJのようなIDEのティーチングを使用するコースを見てきました。これにより、ポイントアンドクリックして任意のメソッドを実行できますが、それらは脇に置いておきます...)これらのキーワードは少しの間、遅かれ早かれほとんどの教師がそれらを説明したいと思うでしょう。実際、古典的な初心者レベルのテスト問題は、基本的なHello Worldプログラムの各キーワードの意味を生徒に尋ねることです。そして、メインメソッドシグネチャの一部として何を見つけますか?配列(その理由の一部は、歴史的です。Java1.0にはArrayListは存在しませんでした)。配列は、その基本的な知識セットの一部です。リストはありません。

とはいえ、特にオブジェクトとその使用方法が説明された後、クラスがコースの少し後にArrayListを導入することは珍しくありません。JavaのAPコンピューターサイエンスカリキュラムでさえArrayListを含んでいます(以前は知っていましたが、Googleはそれがまだあることを示しているようです)が、ArrayListがListおよびその他のCollections Frameworkを実装しているという事実を無視しています。

最後に、大学のCSプログラムは、学生に優れたJava開発者になる方法を教えるのではなく、CSとプログラミングの概念を探る手段としてJavaを使用するという私の経験です。いくつかのプログラムは専門の開発者を駆り立てることに焦点を当てているかもしれませんが、他のプログラムは理論に焦点を当てているかもしれませんが、いずれの場合も、ほとんどの大学のカリキュラムでは教えられない実際の専門的な仕事でJavaを使用する方法について学ぶべきことがたくさんあります。これは、Effective Javaのようなデザインパターンや技術から、Spring、Hibernate、JUnitなどのフレームワーク、またはJSPやJDBCなどのより一般的なものにまで及びます。その哲学を念頭に置いて、より一般的に使用されるArrayListよりも配列を強調することは、もう少し理にかなっています。


3
@Deduplicator確かに。配列についての私のポイントとは関係ないため、省略しました。System.out.println( "Hello World!");も含めませんでした。どちらか。
ザックリプトン

「実世界」の概念対効果的なテクニックに対して+1。少なくとも私が学校にいたときは、誰もバージョン管理を教えていませんでした-しかし、私は古代です:)
デビッド

スケジューラーのようなさまざまな部分を実装する必要があるオペレーティングシステムクラスを取りました。その時点ではそれ以上のことを行うことができなかったため、一度に(排他的に)そのような作品に焦点を当てました。しかし、これらのすべての作品を同時に動作せようとすることを考えたことが、「現実世界」の開発/「大規模プログラミング」の複雑さを理解した(始まりの)理由でした。
デビッド

14

初年度のプログラミングクラスが配列を使用する理由の1つはレガシーです。これは、動的リストを含む標準ライブラリの使用を開始する前に教授が最初に学習した方法です。プリミティブデータ型の使用もより一般的に適用可能です:配列はほとんどすべてのコンピューターに存在します太陽の下での言語(および少数のアセンブリ命令で実装できます)。私がプログラミングを初めて学んだとき、リンクリストを実装することが課題の1つでした。

最初の原則から始めて、「それが基本構造です。この言語(またはそのライブラリ)は、すべてを実行する高レベルのデータ構造を提供しますが、x、y、およびzを提供します」と言う方がはるかに簡単です「つまり、これがこれらの高レベルのデータ構造です。今、ここに隠れているものがあります。」LinkedListとArrayList(またはHashSetとTreeSet)を使用するかどうかを推論することは、通常2年目または3年目のアルゴリズムコースです。リストとマップは同じインターフェースを持ち、同じ結果をもたらしますが、どのサイズのアプリケーションでも動作が劇的に異なる場合があります。プログラミング101を終了すると、プログラミング102が同じ言語を使用するという保証はありません。配列の概念から始める場合、単に「

入門コースで「リスト」よりも「配列」を好むもう1つの理由は、配列が基本的に理解しやすいことです:20の配列bytesは20バイト(さらに、実装に応じて配列の終わりまたは長さを示すカップルが必要です) )。

「リスト」は完全に異なる魚のケトルであり、基本的に異なるパフォーマンス特性を備えたさまざまな方法(ArrayList、LinkedList、おそらくおそらく忘れてしまったカップル)で実装できます。さまざまなListクラスが何をしているのかを理解しなければ、List foo = new ArrayList()vs List foo = new LinkedList(). をいつ使用すべきかについて有意義な議論をすることはできません。生徒にList実装を使用させようとすると、誰かが他の実装の代わりにArrayListを使用している理由を尋ねます。また、「ArrayList」には「Array」という単語が含まれており、その1つに支えられているため、「array」から「ArrayList」への大きなロジックジャンプではありません。

一般に信じられていることとは反対に、特に静的サイズのリストを扱う場合は、リストに対して配列を使用するのが理にかなっている状況があります。ここにカップルがあります:

  • 検索と反復あなたがオーバーヘッドメソッド呼び出しを扱っていないので、わずかに速いです:foo[n]逆参照し、いくつかの舞台裏は算術ポインタん、しばらくはfoo.get(n)間接参照を持って、メソッド呼び出しを行い、第二間接参照を行い、その後、多分ポインタ演算を行います(ArrayListを使用している場合、LinkedListsはListのすべての要素を繰り返し処理する必要がある可能性があります)。
  • 初期化はずっときれいです:int[] foo = new int[]{1, 2, 3, 4, 5}vs. 別のStackOverflow質問の提案

配列が配列を非常に上回る場合の別のシナリオは、要素が利用可能になるシーケンスが、最終位置が既知になるシーケンスと一致するが、最終シーケンスとは一致しない場合です。permint[256]順列を保持している場合、配列を使用して簡単にそれを反転させることint[] inv = new int[256]; for (int i=0; i<256; i++) inv[perm[i]]=i; ができますArrayList<>
-supercat

@supercatこれは、実際には動的配列の問題ではなく、特定の実装に関する問題です。ArrayList特定のサイズのデフォルトで初期化されたリストを作成するコンストラクタを簡単に指定できます。
ドーバル

配列リストがメソッド呼び出しのオーバーヘッドを処理する必要があるという主張を裏付ける情報源はありますか?理論的にはそれはありませんが、実際に私があれば驚かれるだろうgetし、setインライン化されません。
ドーバル

@Doval:適切に設計された言語/フレームワークが、順序をずらしてアイテムを追加するのに便利な動的配列型を提供しない理由はありませんが、Javaはそのような型を提供しません。
スーパーキャット

@Doval:たとえgetsetでライニングすることができ、のようなものはmyList.set(23,myList.get(23)+1)どこにも近いほど効率的となりますmyArray[23]+=1。さらに、ボクシングを必要としないタイプであっても、JITterがfor (i=0; i<1000; i++) myList2.set(i+2000,myList2.get(i+3000));パフォーマンスが近くにあるものに同等のものを提供できる場合、私は非常に驚きSystem.arrayCopy(myArray1,3000,myArray2,2000,1000); ます。しかし、Javaはそうではありません。
スーパーキャット

7

Javaでは、あらゆるタイプの変数を配列に格納できます。対照的に、ArrayList参照の保存のみを許可します。一つは、このように有用に議論しないことがありArrayList、自動ボクシングは参照型にプリミティブを変換する方法、および自動アンボクシングする方法を最初に覆うことなく時々プリミティブへの参照タイプを変換します。

for (int i=10; i<=10000; i*=10)
{
    ArrayList<Integer> l = new ArrayList<Integer>();
    l.add(i);
    l.add(i);
    l.add(l.get(0));
    System.out.print("i=" + i);
    System.out.print(" #0==i:" + (l.get(0)==i));
    System.out.print(" #1==i:" + (l.get(1)==i));
    System.out.print(" #2==i:" + (l.get(2)==i));
    System.out.print(" #0=#1:" + (l.get(0)==l.get(1)));
    System.out.print(" #1=#2:" + (l.get(1)==l.get(2)));
    System.out.println(" #0=#2:" + (l.get(0)==l.get(2)));
}

コードがでint[3]なくを使用していた場合、ArrayList驚くことはありません。3つの要素はすべてi、互いに等しいか等しいかを比較します。ArrayListただし、を使用すると、リストの3つの要素すべてが常にに等しくi、最初と3番目の要素は常に互いに等しく比較されますが、最初の2つの要素は1、10 i、または100 の場合にのみ互いに​​等しくなりますが、 (ほとんどの実装で)i1000または10000の場合ではありません。


#0と#1が1または10または100のときに等しくなる理由を説明できますか?その時点までフォローアップしました。
マシュー

2
@MatthewRead:IntegerクラスにはネストされたクラスがIntegerCacheありInteger、通常-128..127に及ぶ値の範囲に対して事前に初期化されたオブジェクトを保持します。その範囲外の値をボックス化するには、新しいオブジェクトを作成する必要がありますが、キャッシュされた範囲内の値をボックス化すると、に保存されている事前初期化オブジェクトの1つへの参照が返されIntegerCache.cacheます。優れたJavaプログラマーはInteger、同じ値をカプセル化する2つのタイプの変数が等しいかどうかを認識している必要がありますが、そのアイデアを早めに導入すると、生徒は恐怖から逃げ出す可能性があります。
supercat

ええ、事前に初期化されたオブジェクトが原因だとは思いもしませんでした。情報をありがとう!
マシュー

1
@MatthewRead:Javaで特定の種類の暗黙的な変換を許可しないことを望みます==。自動ボックス化解除がスローされる可能性を考えると、私はそれを完全に拒否する傾向がありますが、その動作==は特に恐ろしいです。また、==演算子は16777217==16777216f[reports true]のような場合にひどく振る舞い、暗黙の変換long v=Math.Round(123456789), w=Math.Round(123456789012345)は予期しないものになりがちです[これらの式が何をもたらすか推測できますか?]
supercat

に関してはIntegerCache、確かにパフォーマンスを向上できる場合がありますが、それは頻繁にちょっとした動作をするだけの間違ったコードを頻繁に引き起こす可能性があります。いくつかの方法で、ボクシングが2つの整数キャッシュからオブジェクトを準ランダムに返し、キャッシュアイテムを新しいものに準ランダムに置き換えるモードがあればよいのに、値-128..127のボックス化動作に依存するコードは非常に長い間成功する見込みはありません。
-supercat

6

ArrayList内部的に配列を使用するという事実のため、最初に配列を使用する方法を教えることは理にかなっていると思います。ArrayListクラスは、呼び出されたメンバ変数有しelementDataているObject配列。

JDK ArrayList ソースコードから

/**
 * The array buffer into which the elements of the ArrayList are stored.
 * The capacity of the ArrayList is the length of this array buffer.
 */
private transient Object[] elementData;

要素を追加、更新、取得、または削除するArrayListと、この内部配列を使用してこれらの操作を実行します。ユーザーIxrecが既に指摘しているように、これArrayListは単なる高レベルの抽象化であり、通常は作業が簡単です。


ただし、配列は内部的にメモリブロックへのポインタを使用します。なぜ特定の抽象化レベルから始めるのですか?

質問は次のようにタグ付けされていますJava-通常使用する場合にアレイを教える理由を尋ねていましたArrayList。Javaにはポインターがありません。間違いなく、私はC / C ++はJavaよりも学生を始めるのに適した言語であると考えています。プログラミングの多くのトピックは、C / C ++の知識があればよりよく理解できます。
デレクW

3

あなたが言うように、そのリストは実際に作業しやすいと仮定します-それは本当に重要ではありません。学習は、「簡単から難しい」というよりも「基本から複雑」に関するものです。ファンダメンタルズが重要でなければ、コンピューターサイエンスは学術分野にはなりません。既存のフレームワーク/ライブラリを使用して、オンラインチュートリアルからアプリを一緒にクリックする方法を学ぶことができます。(もちろん、誰かがそれらのライブラリを書く必要があります...そしてArrayList、そもそも誰かが実装しなければなりません....)


多くの場合、その使用ArrayListは別の配列と「liveItems」カウントを使用することでより適切に処理できます。ただし、配列を操作し、集計する以外に一緒にカウントする便利な方法はありません。
-supercat

2

アカデミック教育で最も重要なことは、正しい用語を使用して自分のやることを説明することを教えることだからです。

リストはその配列以外のものです。またjava.util.List、Javaはインターフェースであるため使用できません。通常java.util.ArrayList、List実装であるwhichはリストではなく、動的配列のオブジェクトラッパーを使用します。したがって、「リスト」を使用すると言いますが、配列を使用します。

その用語のカオスをスキップし、配列を使用して生徒に配列とは何かを学ぶことは非常に合理的です。Javaで配列を使用する場合、少なくとも配列を使用します。

正直なところ、Javaでプログラミングを教えるのが良い考えではない理由も論点です。プログラミングの基本概念を正しく学ぶことは困難です。


ハッシュマップはどうですか?配列は、ある意味では単なるハッシュマップの一種です
。.-Thufir

@Thufir配列をハッシュマップにするにはどうすればよいですか?これらは完全に異なるデータ構造です。
ダヌビアセーラー

ハッシュマップで配列を表すことができます。どちらがより「基本的」ですか?ハッシュマップは概念的にもっと興味深いと主張します。
トゥフィル

1
@Thufirいいえ、できません。エミュレートのみ可能です。内部的には、各データ構造がそのままになります。これらは根本的および概念的に異なるものです。これが、JavaやJavaScriptのような非常に抽象的な言語でプログラミングの学習を始めるのが悪い考えである理由です。そこでは、データ構造が実際に何であるかは明確ではありません。
ダヌビアセーラー

1

文字通り配列を見たことがなく、まったく使用したことがありませんか?リストに加えて、常にそれらを使用します。通常、Javaは使用しませんが、明らかな類似性を引き出す他の多くの言語を使用します。

配列とリストの間では、一方がより軽量で、さらにポイントが多くなりますが、もう一方はより多くの機能を持ちます。プログラミングの一般的なルールとして、基本的にそれらの線に沿って分割される2つの類似したタイプがある場合、実際に手の込んだものが必要でない限り、軽量のものを選択する必要があります。これは、オーバーヘッドを削減することに加えて、実際にはプログラムと特にそのコードの混乱と状態の量を把握するのに役立ちます。テスト中に問題が発生した場合、見る場所が少なくなります。さらに重要なのは、配列とリストの場合、人々はあなたが実際にそれを使って何をしようとしているかの限られた範囲についてのより良いアイデアを得ます。

そしてええ、学術的な観点から、学生に基本を教えることの追加の理由があります。ただし、これはもう少し深くなります。配列とリストは、より軽量な型の基礎となるインスタンスの上に構築され、頻繁に単にラップされるだけの、より大きな型の良い例です。リストに基本的な配列がない場合でも、リストのように外向きに動作します。リストとは何かを誰かに教えることの一部は、配列とは何かを教えることです。

これは、C ++のような言語では手に負えなくなる可能性があります。C++では、基本的に配列を削除することはできませんが、高レベル言語では、ほとんどリストになります。与えられた状況で彼らがあなたのニーズに完全に合っているなら、なぜあなたは何か他のものを使う必要があるでしょうか?


リストに「異なる」機能がある限り、「より多くの」機能があるとは言いません。新しいものT[]は、ゲートからすぐに、任意の順序でアイテムを受け入れる準備ができていますが、変更するにはアイテムを順番にArrayList<T>追加する必要があります。A T[]は任意の範囲のアイテムを同じサイズの別の範囲にT[]比較的迅速にコピーできますが、ArrayList<T>1つのリストから個別にアイテムを読み取り、他のリストに保存する必要があります。
-supercat
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.