Javascriptで配列キーを取得する方法は?


80

このコードで作成された配列があります:

var widthRange = new Array();
widthRange[46] = { min:0,  max:52 };
widthRange[66] = { min:52, max:70 };
widthRange[90] = { min:70, max:94 };

46、66、90の各値をループで取得したいと思います。私は試しましたfor (var key in widthRange)が、これは私にたくさんの追加のプロパティを与えます(私はそれらがオブジェクトの関数であると思います)。値がシーケンシャルではないため、通常のforループを使用できません。


9
たまたま数値キーがありますが、実際には配列データではないデータがあるようです。ここでは、通常のオブジェクトを使用することを検討します。
クエンティン

@Quentinこれはスパース配列と呼ばれます。パフォーマンス面では、ここではオブジェクトの代わりに配列を使用するのが最善です。また、パフォーマンスに関しては、ベストアンサーはリストされていませんArray.prototype.forEachObject.keys配列を呼び出すと、ブラウザが配列を最適化しないため、パフォーマンスが低下します。for(var key in array)プロトタイプをトラバースし、検出した各数値キーを文字列化するため、これは悪いことです(doubleをbase10に変換するのは非常に遅いです)。forEachただし、スパース配列を反復することを目的として正確に設計されており、他のソリューションと比較してコードに優れたパフォーマンスを提供します
Jack Giffin 2010年

回答:


96

次のように、hasOwnProperty関数を呼び出して、プロパティが(プロトタイプではなく)オブジェクト自体に実際に定義されているかどうかを確認する必要があります。

for (var key in widthRange) {
    if (key === 'length' || !widthRange.hasOwnProperty(key)) continue;
    var value = widthRange[key];
}

の個別のチェックが必要であることに注意してくださいlength
ただし、ここでは配列を使用しないでください。通常のオブジェクトを使用する必要があります。すべてのJavascriptオブジェクトは、連想配列として機能します。

例えば:

var widthRange = { };  //Or new Object()
widthRange[46] = { sel:46, min:0,  max:52 };
widthRange[66] = { sel:66, min:52, max:70 };
widthRange[90] = { sel:90, min:70, max:94 };

2
本当に?うわー、私はここで毎日何かを学びます、そしてそれはあなたから頻繁にSLaksです:-) Arrayがそのように明示的に設定されたインデックスを追跡していることに驚いています。多分私はすべきではありません。
先のとがった

@SLaks:ありがとう、それをオブジェクトに変更するのが最も良い解決策のようです。もう1つの質問:逆の順序で繰り返す方法はありますか?
DisgruntledGoat 2010年

番号; あなたはそれを自分でする必要があるでしょう。
SLaks 2010年

2
なぜ別のチェックが必要なのlengthですか?[[DontEnum]]すべてのブラウザでマークされていませんか?
Roatin Marth 2010

@Roatin:わかりません。転ばぬ先の杖。
SLaks 2010年


18

配列/コレクションの操作や検査を行う場合は、Underscore.jsを使用することを強くお勧めします。それは小さく、十分にテストされており、JavaScriptの頭痛の種を数日/数週間/数年節約できます。キー機能は次のとおりです。

キー

オブジェクトのプロパティのすべての名前を取得します。

_.keys({one : 1, two : 2, three : 3});
=> ["one", "two", "three"]

4

配列がarr = [ { a: 1, b: 2, c: 3 }, { a: 4, b: 5, c: 6 }, { a: 7, b: 8, c: 9 } ](またはおそらく他のキー)のように見えたとし ましょう

arr.map((o) => {
    return Object.keys(o)
}).reduce((prev, curr) => {
    return prev.concat(curr)
}).filter((col, i, array) => {
    return array.indexOf(col) === i
});

["a", "b", "c"]


3
for (var i = 0; i < widthRange.length; ++i) {
  if (widthRange[i] != null) {
    // do something
  }
}

配列が機能する方法ではないため、設定したキーだけを実際に取得することはできません。要素46を設定すると、0から45も設定されます(ただし、これらはnullです)。

常に2つの配列を持つことができます。

var widthRange = [], widths = [], newVal = function(n) {
  widths.push(n);
  return n;
};
widthRange[newVal(26)] = { whatever: "hello there" };

for (var i = 0; i < widths.length; ++i) {
  doSomething(widthRange[widths[i]]);
}

よく編集してください私はここですべて濡れているかもしれません...


配列は長さを追跡するだけであり、通過していくら多くのオブジェクトを作成することはありません。基本的に、新しいインデックスが見つかると、その新しいインデックスが長さよりも大きいかどうかを確認します...新しいインデックスが新しい長さになる場合。そのため、for-inループで定義したインデックスのみを取得することが可能です
Bob


1

あなたの元の例は私にとってはうまく機能します:

<html>
<head>
</head>
<body>
<script>
var widthRange = new Array();
widthRange[46] = { sel:46, min:0,  max:52 };
widthRange[66] = { sel:66, min:52, max:70 };
widthRange[90] = { sel:90, min:70, max:94 };

var i = 1;
for (var key in widthRange)
{
    document.write("Key #" + i + " = " + key + "; &nbsp;&nbsp;&nbsp; min/max = " + widthRange[key].min + "/" + widthRange[key].max + "<br />");
    i++;
}
</script>
</html>

ブラウザでの結果(WindowsXPではFirefox3.6.2):

Key #1 = 46;     min/max = 0/52
Key #2 = 66;     min/max = 52/70
Key #3 = 90;     min/max = 70/94

2
彼はプロトタイプかそのようなものをインポートしているに違いない。一般に、これらの「イン」ループは危険です。
とがった2010年

私はjQueryを使用していますが、mootoolsを使用するJoomlaも使用しています。何かがそれらのプロパティを追加しています。
DisgruntledGoat 2010年

1

これに{}は、配列([])ではなくオブジェクト()を使用する必要があると思います。

データのセットが各キーに関連付けられています。オブジェクトを使うと悲鳴を上げます。行う:

var obj = {};
obj[46] = { sel:46, min:0,  max:52 };
obj[666] = { whatever:true };

// This is what for..in is for
for (var prop in obj) {
  console.log(obj[prop]);
}

たぶん、このようないくつかのユーティリティのものが役立つことがあります:

window.WidthRange = (function () {
  var obj = {};
  return {
    getObj: function () {return obj;}
    , add: function (key, data) {
        obj[key] = data;
        return this; // enabling chaining
      }
  }
})();

// Usage (using chaining calls):
WidthRange.add(66, {foo: true})
.add(67, {bar: false})
.add(69, {baz: 'maybe', bork:'absolutely'});

var obj = WidthRange.getObj();
for (var prop in obj) {
  console.log(obj[prop]);
}

0

動作しているようです。

var widthRange = new Array();
widthRange[46] = { sel:46, min:0,  max:52 };
widthRange[66] = { sel:66, min:52, max:70 };
widthRange[90] = { sel:90, min:70, max:94 };

for (var key in widthRange)
{
    document.write(widthRange[key].sel + "<br />");
    document.write(widthRange[key].min + "<br />");
    document.write(widthRange[key].max + "<br />");
}

0

オブジェクトのすべてのインスタンスで正常に機能する関数を作成しました(配列はそれらです)。

Object.prototype.toArray = function()
{
    if(!this)
    {
      return null;
    }

    var c = [];

    for (var key in this) 
    {
        if ( ( this instanceof Array && this.constructor === Array && key === 'length' ) || !this.hasOwnProperty(key) ) 
        {
            continue;
        }

        c.push(this[key]);
    }

    return c;
};

使用法:

var a   = [ 1, 2, 3 ];
a[11]   = 4;
a["js"] = 5;

console.log(a.toArray());

var b = { one: 1, two: 2, three: 3, f: function() { return 4; }, five: 5 };
b[7] = 7;

console.log(b.toArray());

出力:

> [ 1, 2, 3, 4, 5 ]
> [ 7, 1, 2, 3, function () { return 4; }, 5 ]

それは誰にとっても役に立つかもしれません。


2
自分で作成しなかったプロトタイプを拡張することは、どんなに便利だと思っても、非常に悪い考えです。
doug65536 2013

0

... ????

または、使用したいアイテムのリストがある場合...

var range = [46, 66, 90]
    , widthRange=[]
    , write=[];

    widthRange[46] = { min:0, max:52 }; 
    widthRange[66] = { min:52, max:70 }; 
    widthRange[90] = { min:70, max:94 }; 

for(var x=0; x<range.length; x++){var key, wr;

    key = range[x];

    wr = widthRange[key] || false;

    if(wr===false){continue;}

    write.push(['key: #',key, ', min: ', wr.min, 'max:', wr.max].join(''));

    }

0

入力データの場合:

let widthRange = new Array()
widthRange[46] = { min:0,  max:52 }
widthRange[61] = { min:52, max:70 }
widthRange[62] = { min:52, max:70 }
widthRange[63] = { min:52, max:70 }
widthRange[66] = { min:52, max:70 }
widthRange[90] = { min:70, max:94 }

宣言型アプローチ:

const relevantKeys = [46,66,90]
const relevantValues = Object.keys(widthRange)
    .filter(index => relevantKeys.includes(parseInt(index)))
    .map(relevantIndex => widthRange[relevantIndex])

Object.keysキーを取得するには、を使用parseIntしてキーを数字としてキャストします。 filter欲しいものだけを手に入れましょう。 map後のインデックスだけの元のオブジェクトから配列を構築するObject.keysオブジェクトの値が失われるためます。

デバッグ:

console.log(widthRange)
console.log(relevantKeys)
console.log(relevantValues)

0

質問はかなり古いですが、最近ではforEachを使用できます。これは効率的で、キーを数字として保持します。

let keys = widthRange.map((v,k) => k).filter(i=>i!==undefined))

これはwidthRangeをループし、キーの値を使用して新しい配列を作成し、定義された値のみを取得してすべてのスパーススロットを除外します。

(悪い考えですが、徹底のために:スロット0が常に空である場合、それはfilter(i=>i)またはに短縮される可能性がありますfilter(Boolean)

そして、それは効率が悪いかもしれませんが、数字はでキャストすることができます let keys = Object.keys(array).map(i=>i*1)

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.