質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

88.04%

【C#】配列の要素の削除についての質問です。

受付中

回答 4

投稿

  • 評価
  • クリップ 0
  • VIEW 20K+

score 6

配列の特定(null)のものを削除し、削除されたものを読みたい。

現在、データテーブルから持ってきたデータを配列の要素に代入しているのですが、
代入されていないnullの要素を削除したいと思っております。
現在行っている処理としては、

        static void Main(string[] args)
        {

            //null配列は呼び出さない処理。

            string[] tn = new string[10];
            tn[0] = "hoge";


            //nullデータがあった場合その要素を削除する
            for (int i = 0; i < tn.Length; ++i)
            {

                if (tn[i] != null)
                {
                }
                else{
                    List<string> numberList = new List<string>(tn);
                    numberList.RemoveAt(i);
                    //要素のコピー
                    tn = numberList.ToArray();
                }

            }
            for (int i = 0; i < tn.Length; ++i)
            {

                if (tn[i] == null)
                {
                    Console.WriteLine("null");

                }

                //途中で消えるため、エラー
                Console.WriteLine(tn[i]);

            }

この処理を実行すると、何故か、5つだけ要素は消えるのですが、他のものが消えてくれません。。。

ですが、

        static void Main(string[] args)
        {

            //null配列は呼び出さない処理。

            string[] tn = new string[10];
            tn[0] = "hoge";


            //nullデータがあった場合その要素を削除する
            for (int i = 0; i < tn.Length; ++i)
            {

                if (tn[i] != null)
                {
                    List<string> numberList = new List<string>(tn);
                    numberList.RemoveAt(i);
                    //要素のコピー
                    tn = numberList.ToArray();
                }

            }
            for (int i = 0; i < tn.Length; ++i)
            {

                if (tn[i] == null)
                {
                    Console.WriteLine("null");

                }


                Console.WriteLine(tn[i]);

            }

このように、nullのもの以外消すという処理にすると、hogeは消えてくれます。

RemoveAtに削除できる上限があるということなのでしょうか??

分かる方、よろしくお願いします。

  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 過去に投稿した質問と同じ内容の質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 4

+4

using System;
using System.Linq;

namespace Test
{
    class Program
    {
        static void Main()
        {
            string[] tn = new string[10];
            tn[0] = "hoge";

            foreach(var _t in tn.Where(e => e != null))
            {
                // nullが入っていないことを知るためにあえて判定。
                Console.WriteLine(_t == null ? "null" : _t);
            }
        }
    }
}


Linqでnull以外の要素を取り出して
配列にするという方法はどうでしょうか。

補足

Tak1016様の回答を見て、コードを書き換えました。

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

+2

using System;
using System.Collections.Generic;
using System.Linq;

namespace Answer86902
{
    class Program
    {
        static void Main(string[] args)
        {
            var tn = new string[10];

            tn[0] = "hoge";

            var counter = 0;

            do
            {
                if (tn[counter] == null)
                {
                    var remover = new List<string>(tn);
                    remover.RemoveAt(counter);
                    tn = remover.ToArray();

                    Console.WriteLine($"Nullを検知したため{counter}番目の要素を削除しました");
                }
                else
                {
                    counter++;
                }
            } while (counter < tn.Length);

            Console.WriteLine($"配列tnの要素数は{tn.Length}です。");
            tn.ToList().ForEach(Console.WriteLine);
        }
    }
}

上の皆さんが採用しているForのカウンタ弄りはやるべきではないです。あくまで順次処理なのでLINQを使わない場合はWhile文を採用すべきです。

using System;
using System.Collections.Generic;
using System.Linq;

namespace Answer86902
{
    class Program
    {
        static void Main(string[] args)
        {

            var tn = new string[10];
            tn[0] = "hoge";

            tn = tn.Where(val => val != null).ToArray();

            Console.WriteLine($"配列tnの要素数は{tn.Length}です。");
            tn.ToList().ForEach(Console.WriteLine);
        }
    }
}

ただC#ならやっぱりLINQを採用すべきなのでC#的にはこっちのほうがいいと思います。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2017/08/03 22:16

    勉強になります。

    キャンセル

  • 2017/08/04 02:04

    Forのカウンタ弄りはやるべきではないです。あくまで順次処理なのでLINQを使わない場合はWhile文を採用すべきです。

    とのことですが、やるべきではない理由を具体的にお聞かせいただいてもよろしいでしょうか。僕自身、for文のキーをデクリメントする方法を稀に使っているので今後使用しないようにしますが、過去に書いたプログラムを修正した方が良いか判断したいです。大変お手数ですがよろしくお願いいたします。

    キャンセル

  • 2017/08/04 18:30

    バグを生む未来しかないからだよ。予期しない無限ループや配列の範囲外アクセスが簡単にできてしまう。だから、基本的に、For文ではなく、Foreachを使おうということになっている。

    キャンセル

  • 2017/08/04 22:01

    了解しました。以後使用しないようにします。ご返答ありがとうございました。

    キャンセル

+2

えーっと 回してる配列をRemoveしたらだめですよ。

int[] tn= new int[] {0,1,2,3,4,5,6,7,8,9};


for(int i=0; i < tn.Length; i++) 
{
  List<string> numberList = new List<string>(tn);
    numberList.RemoveAt(i);
    tn = numberList.ToArray();
}

これを実行すると
i=0 のとき 実行後のtnは { 1,2,3,4,5,6,7,8,9 }  0番目の要素0が消えた。
i=1 のとき 実行後のtnは { 1,3,4,5,6,7,8,9 }    1番目の要素2が消えた。消えるのは1ではない。
i=2 のとき 実行後のtnは { 1,3,5,6,7,8,9 }      2番目の要素4が消えた。
i=3 のとき 実行後のtnは { 1,3,5,7,8,9 }         3番目の要素6が消えた。

となります。ループしている配列やList,Collectionから要素を削除してはいけません。

関数型プログラミングのLinqを使いましょう。

var nullItems = tn.Where(n=> n == null).ToArray();
var notNullItems = tn.Where(n=> n != null).ToArray();

ToArray()
を実行すると 新しい配列のインスタンスが作られますので無駄です。

必要な時にIEnumerableのままループすると遅延実行(yield return)により無駄なく処理されます。

foreach(var n in tn.Where(n=> n == null))
{
   Debug.WriteLine(n);
}

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2017/08/03 22:44

    勉強になります。

    キャンセル

+1

[追記] キーのデクリメントは推奨しないとの事でしたので使用しないでください。

消えてなくなったのでデクリメントしないといけないですね。

        string[] tn = new string[10];
        tn[0] = "hoge";


        //nullデータがあった場合その要素を削除する
        for (int i = 0; i < tn.Length; ++i)
        {

            if (tn[i] != null)
            {
            }
            else
            {
                List<string> numberList = new List<string>(tn);
                numberList.RemoveAt(i);
                //要素のコピー
                tn = numberList.ToArray();
                //※ デクリメント 非推奨 ※
                i--;
            }

        }
        for (int i = 0; i < tn.Length; ++i)
        {

            if (tn[i] == null)
            {
                Console.WriteLine("null");

            }

            //途中で消えるため、エラー
            Console.WriteLine(tn[i]);

        }

その他の方法

一旦リストにして削除

        string[] tn = new string[10];
        tn[0] = "hoge";


        List<string> _tn = new List<string>(tn);
        _tn.RemoveAll(o => o == null);
        tn = _tn.ToArray();

        for (int i = 0; i < tn.Length; ++i)
        {

            if (tn[i] == null)
            {
                Console.WriteLine("null");

            }

            //途中で消えるため、エラー
            Console.WriteLine(tn[i]);

        }

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 88.04%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

同じタグがついた質問を見る