javascriptの勉強をしています。

今回は2つの質問です。

1)for文のループに関してで、
ある数字に含まれている(その数字より小さい)奇数だけパイプ線で区切りたいのですが、
こんな感じ→  1|3|5|7|9|・・・(ある数字(例:15))

for(var j=1;j<=15;j++)
document.write(2*j-1+"|");

とdocument.writeを使えばうまくいくのですが、
他の方法で要素を結合しようとすると、

for(var j=1;j<=15;j++)
document.myForm.data.value=2*j-1+"|";

ループが終了していて1番高い数字が1つだけ表示されてしまいます。
調べたところクロージャなどを使って解決するようなのですが、
いまいち理解ができないのでよろしくお願いします。

2)ある配列から最小を求めるときに、
var min = Math.min.apply(null, hairetu);

ある限定の数字(例えば-5)が最小の場合は、
その要素(-5)の次に最小の要素を求める場合はどう書けばいいでしょうか?
(ようは-5だけは最小にしたくない)

また同じように、負(マイナス)の要素を相手にせずに、
正(プラス)だけの最小値を求める場合はどう書けばよいでしょうか?

分かりにくいようなら追記いたします。よろしくお願いします。

回答の条件
  • 1人5回まで
  • 登録:2009/04/21 16:45:05
  • 終了:2009/04/22 15:07:16

ベストアンサー

id:kebo987654 No.2

kebo987654回答回数38ベストアンサー獲得回数102009/04/21 23:03:29

ポイント100pt

1)

たとえば

string+="abcd";

なら

string=string+"abcd";

と同じ意味になりまから、

document.myForm.data.value+=~;

としてしまうと、

document.myForm.data.value=document.myForm.data.value+~;

のように現在フォームに書かれている文字列に~を加えることになります。

ですから文字列をいったん格納する変数を用意しておいて、変数のなかで文字列を完成させてから代入させてやるとうまくいきます。

var str="";//最初に空文字列を定義します。
for(var j=1;j<=15;j+=2)
     str+=j+"|";//定義した文字列変数に文字列を足していきます。
document.myForm.data.value=str;//完成した文字列を表示します。

ただ、JavaScriptで文字列を何回も結合したい場合は、+演算子を使うよりも

配列.join("")とする方が効率が高い場合が多いです。(ブラウザにもよりますがIEなら確実にそうなります)

例:

var l=(15/2>>0)+15%2,//配列の長さ(ループ回数)は予め求められる
    str=new Array(l);
for(var i=0;i<l;++i)
    str[i]=i*2+1;
str.join("|");//ついでに区切り文字"|"を指定して結合するとよりスマート?

2)

正の最小値の求め方ですが、

負の数は符号なし整数にしてしまえば正の数よりも必ず大きい数になりますから、整数のみを扱うのでしたら配列に代入する時点で符号なし整数にしておいてMath.min.applyすればいいと思います。

/*x>>>0で符号なし整数にできる*/
var array=[-8>>>0,-4>>>0,0>>>0,1>>>0];

/*負が正より大きくなっているので、正の最小値0が表示される*/
Math.min.apply(null,array);//0

/*配列から値を取り出すときはx>>0のようにして符号付きに戻す*/
array[0]>>0;//-8
id:tontonpokopoko

kebo987654さま、いつもありがとうございます。

1)の説明も分かりやすく書いていただいて、とても勉強になりました。

2)の方法はビット演算子というやつでしょうか。

今まで勉強したことがないので、もう少し具体的に教えてもらえないでしょうか?

例えば、

前回のリストボックスでユーザに書き込んでもらった値の配列が「ret」にあります。

この場合はどう書けばいいでしょうか?

「ret」にある正の最小値の求め方です。

よろしくお願いします。

2009/04/22 13:58:29

その他の回答(2件)

id:van-dine No.1

van-dine回答回数108ベストアンサー獲得回数112009/04/21 18:16:45

ポイント70pt

(1)

document.myForm.data.value += 2 * j - 1 + "|";

「+=」ではなく「=」を使ってるため変になります。

(2)

hairetu2 = (hairetu.concat()).sort(function (x, y){return x - y})
for(var i = hairetu2.length - 1; hairetu[i] == hairetu[hairetu2.length - 1]; i--)
//正の時は「~; hairetu[i] > 0; ~」
{
  min = hairetsu[i];
}

1行にはなりませんでしたが、これで動きます。

なお、

(hairetu.concat()).sort(~)

と書かずに

hairetu.sort(~)

と書くと、hairetsuがソートされてしまうのでご注意を。

id:tontonpokopoko

van-dineさま、回答をありがとうございます。

1)の質問ですが参考になります。

もし動的なページ(ある数字、例でいうと「15」が一定ではない)でイベントハンドラで動作した場合に、

1|3|5|7|9|・・1|3|5|7|9|・・1|3|5|7|9|・・(3回クリック)

とイベント(クリック)をするごとに前回の値(セット)の上に足されるようですが、

これを最後にイベントを起こしたセットだけにはできないでしょうか?

1|3|5|7|9|・・を1セットと言う意味です。

2)の質問は検証中です。

2009/04/21 21:45:46
id:kebo987654 No.2

kebo987654回答回数38ベストアンサー獲得回数102009/04/21 23:03:29ここでベストアンサー

ポイント100pt

1)

たとえば

string+="abcd";

なら

string=string+"abcd";

と同じ意味になりまから、

document.myForm.data.value+=~;

としてしまうと、

document.myForm.data.value=document.myForm.data.value+~;

のように現在フォームに書かれている文字列に~を加えることになります。

ですから文字列をいったん格納する変数を用意しておいて、変数のなかで文字列を完成させてから代入させてやるとうまくいきます。

var str="";//最初に空文字列を定義します。
for(var j=1;j<=15;j+=2)
     str+=j+"|";//定義した文字列変数に文字列を足していきます。
document.myForm.data.value=str;//完成した文字列を表示します。

ただ、JavaScriptで文字列を何回も結合したい場合は、+演算子を使うよりも

配列.join("")とする方が効率が高い場合が多いです。(ブラウザにもよりますがIEなら確実にそうなります)

例:

var l=(15/2>>0)+15%2,//配列の長さ(ループ回数)は予め求められる
    str=new Array(l);
for(var i=0;i<l;++i)
    str[i]=i*2+1;
str.join("|");//ついでに区切り文字"|"を指定して結合するとよりスマート?

2)

正の最小値の求め方ですが、

負の数は符号なし整数にしてしまえば正の数よりも必ず大きい数になりますから、整数のみを扱うのでしたら配列に代入する時点で符号なし整数にしておいてMath.min.applyすればいいと思います。

/*x>>>0で符号なし整数にできる*/
var array=[-8>>>0,-4>>>0,0>>>0,1>>>0];

/*負が正より大きくなっているので、正の最小値0が表示される*/
Math.min.apply(null,array);//0

/*配列から値を取り出すときはx>>0のようにして符号付きに戻す*/
array[0]>>0;//-8
id:tontonpokopoko

kebo987654さま、いつもありがとうございます。

1)の説明も分かりやすく書いていただいて、とても勉強になりました。

2)の方法はビット演算子というやつでしょうか。

今まで勉強したことがないので、もう少し具体的に教えてもらえないでしょうか?

例えば、

前回のリストボックスでユーザに書き込んでもらった値の配列が「ret」にあります。

この場合はどう書けばいいでしょうか?

「ret」にある正の最小値の求め方です。

よろしくお願いします。

2009/04/22 13:58:29
id:uunfo No.3

uunfo回答回数46ベストアンサー獲得回数32009/04/22 02:06:31

ポイント30pt

イベント(クリック)をするごとに前回の値(セット)の上に足されるようですが、

これを最後にイベントを起こしたセットだけにはできないでしょうか?

以下のようにすればいいのでないかな。

毎回値を初期化するということ。

document.myForm.data.value="";
for(var j=1;j<=15;j++)
document.myForm.data.value+=2*j-1+"|";
id:tontonpokopoko

回答をありがとうございます。

すでに解決済みでしたが、

他の質問の動作確認のため質問を締め切らず申し訳ありませんでした。

参考にさせていただきます。

2009/04/22 13:37:00
  • id:kn1967
    (1)
    document.write は追記(HTML文を順次作成している)ので
    1|の後に3|さらに5|・・・と続いていきますが
    document.myForm.data.value = は代入(既存の値を無視して、新しい値を入れ)てしまいます。

    以前の値のお尻に値を追加したいのであれば代入(=)ではなく加算(+=)演算子を用います。
    document.myForm.data.value += 2*j-1+"|";

    逆順の場合は、既存の値を式で用いるように記述します。
    document.myForm.data.value = 2*j-1+"|" + document.myForm.data.value;

    (2)
    美しい例ではないけれど、下記のような感じで自作関数を作ると便利かもしれません。
    function min2(v1, v2){
    v3 = v2.sort();
    for (i = 0; i < v3.length; i++) {
    if (v3[i] > v1) { return v3[i] }  ←v1の値以上なら値を返すという式
    }
    return 'none';  ←該当なしの場合はnoneと返すという式
    }

    var hairetu = [4, 10, 5, -5, -2, 10, 3, 2, 6];
    var min = min2(-5, hairetu);
    document.write(min);

    説明文考えている間に、回答ついたようなのでコメント欄で・・・。
  • id:tontonpokopoko
    kn1967さま、わざわざこちらに書き込んでもらい申し訳ありません。
    回答がとても分かりやすく参考になります。

    現在質問、2)は動作確認中ですが、
    1)では、上記の返信に書き込んだとおり、
    1|3|5|7|9|・・1|3|5|7|9|・・1|3|5|7|9|・・(3回クリック)
    セット値が繰り返し増えることを問題としています。
    解決案があったらぜひご教授いただければと思います。
  • id:tontonpokopoko
    kn1967さま、
    2)の質問ですが配列の要素がsortで左から小さい順番に変更されているのでしょうか?
    入力された順番(初期の順番)で使いたい場合はどうすればいいでしょうか?
    よろしくお願いします。
  • id:kn1967
    >セット値が繰り返し増える

    ループの前で
    document.myForm.data.value = '';
    という処理を行って一旦空っぽにします。

    >配列の要素がsortで左から小さい順番に変更されている
    v3 = v2.sort();
    の動作はv2でソートを行い、その結果をv3に代入するという動作になってますから
    関数内でいろいろ弄る場合を除けば、実はあまり意味のなく、良い例ではありませんでした。
    話はそれますが、sortの動作は実にあいまいで不確実なため
    van-dine氏の回答にありますようにsort順を明確に示しておくほうがよかったりします。
    さらに、変数のスコープ(生存期間)も考慮して
    varでローカル変数(この場合はfunction内だけで使える変数という意味)とするようにすると
    function min2(v1, v2){
      var v3 = (v2.concat()).sort(function (x, y){return x - y})
      for (var i = 0; i < v3.length; i++) {
        if (v3[i] > v1) { return v3[i] }
      }
      return 'none';
    }
    といったような具合に書き換えてみてください。
    (インデントは全角スペースで行ったので半角スペースに変えてくださいね)
  • id:tontonpokopoko

    kn1967さま、回答をありがとうございます。
    求めていた動作がばっちりです。
    参考までに、入れ子?の「return x - y」は何を書いているのでしょう?

    *おまけ
    正常に動作をしなくて、昨日は解決できませんでした。
    そして最初のソートするものに触っているうちに解決しました。
    全角スペースは使えないと理解はしていたのですが、
    とりあえず動作確認とか思っていたのが失敗の元でした。
    わざわざ注意まで書いてくださっていたのに・・・いい勉強になりました。
  • id:tontonpokopoko
    kn1967さま、コメント欄でお書きいただいたため、
    こちらからのお礼が出来なくて大変申し訳ありませんでした。
    試してみたいことがたくさんあり、
    また疑問がすぐに沸くと思いますが、どうぞまたよろしくお願いいたします。
  • id:kn1967
    私のコメント投稿の2時間後に
    同じ内容(しかも一部分だけ)のような投稿に
    ポイント配る必要は無いかと思いますし
    ワザとして、符号付/無などは将来役立つかもしれませんが
    プログラムの基礎を学ぶ段階で学習するものかどうかは疑問。
    ベストアンサー無しが妥当かと思いますね。

    それはさておき
    sortは値を1対1で比較して並び替えるのですが
    その際に(かっこ)の中の値で並びを決めます。
    1対1をそれぞれxとyとして関数に与えて
      x-y の値が プラスなら x が大きい
      x-y の値が マイナスなら y が大きい
      ゼロなら 当然同じ。
    という対応をとります。

    なお、
    特にポイントが欲しい訳ではないのでお気持ちだけで結構です。
  • id:tontonpokopoko
    kn1967さま、ありがとうございます。
    sortの使い方を参考にさせていただきます。

    ポイントの配り方の基準はよくわかりませんが、
    私にとっては理解が深まるものこそが1番と思っています。
    質問の要領が悪いのかもしれませんが、
    同じレベルで説明してくれることがとても役に立っています。

この質問への反応(ブックマークコメント)

「あの人に答えてほしい」「この質問はあの人が答えられそう」というときに、回答リクエストを送ってみてましょう。

これ以上回答リクエストを送信することはできません。制限について

絞り込み :
はてなココの「ともだち」を表示します。
回答リクエストを送信したユーザーはいません