オブジェクトの配列の値に対して.joinを実行する


274

文字列の配列がある場合、次のように、.join()メソッドを使用して、各要素をコンマで区切った単一の文字列を取得できます。

["Joe", "Kevin", "Peter"].join(", ") // => "Joe, Kevin, Peter"

オブジェクトの配列があり、その中に保持されている値に対して同様の操作を実行したいと思います。から

[
  {name: "Joe", age: 22},
  {name: "Kevin", age: 24},
  {name: "Peter", age: 21}
]

以前と同じ出力を実現するにはjoinname属性に対してのみメソッドを実行します。

現在、私は次の機能を持っています:

function joinObj(a, attr){
  var out = [];

  for (var i = 0; i < a.length; i++){
    out.push(a[i][attr]);
  }

  return out.join(", ");
}

そのコードには何も問題はありませんが、機能しますが、突然、私は単純なコード行から非常に命令的な関数に移行しました。これを書くためのより簡潔で、理想的にはより機能的な方法はありますか?


2
例として1つの言語を使用するには、Pythonでこれを行う方法は次のようになります" ,".join([i.name for i in a])
jackweirdy

6
ES6ではこれを行うことができますusers.map(x => x.name).join(', ');
totymedli 2017年

回答:


497

オブジェクトを何か(この場合はプロパティ)にマップする場合。Array.prototype.map機能的にコーディングしたいなら、あなたが探しているものだと思います。

[
  {name: "Joe", age: 22},
  {name: "Kevin", age: 24},
  {name: "Peter", age: 21}
].map(function(elem){
    return elem.name;
}).join(",");

最近のJavaScriptでは:

[
  {name: "Joe", age: 22},
  {name: "Kevin", age: 24},
  {name: "Peter", age: 21}
].map(e => e.name).join(",");

(フィドル)

ES5に準拠していない古いブラウザーをサポートしたい場合は、シムすることができます(上記のMDNページにポリフィルがあります)。別の代替pluck方法は、underscorejsのメソッドを使用することです。

var users = [
      {name: "Joe", age: 22},
      {name: "Kevin", age: 24},
      {name: "Peter", age: 21}
    ];
var result = _.pluck(users,'name').join(",")

1
これです。ただし、このレトロブラウザーをサポートする必要がある場合は、IE <9の.mapプロトタイプメンバーをshimする必要があります。
Tommi 2013年

1
@トミ良いコメント。アンダーフィルを使用する場合は、pluckを使用するよう提案するとともに、ポリフィルについての説明を追加しました。
Benjamin Gruenbaum 2013年

@jackweirdy :) map / reduce / filterが 'pythonic'ではなく、理解が他の方法で成り立っているのと同じように、それが価値あるものであることを嬉しく思います:) JavaScriptの新しい仕様が進行中(Harmony)と一部のブラウザー(firefox)には、Pythonの理解があります。できる[x.name for x of users](spec wiki.ecmascript.org/doku.php?id=harmony:array_comprehensions)。map / reduce / filterを使用するのと同じように非常に「pythonic」ではないことを言及する価値はありますが、おそらくJavaScriptで他の方法が成り立ちます。coffeescript.orgを介して、CoffeeScriptはそれらと一緒にクールです。
Benjamin Gruenbaum 2013年

1
単なる更新-配列の内包表記はES6から削除されました。ES7で取得できる可能性があります。
Benjamin Gruenbaum 2014年

users.map((obj) -> obj.name).join(', ')
Kesha Antonov

71

まあ、あなたはいつでもtoStringあなたのオブジェクトのメソッドをオーバーライドすることができます:

var arr = [
    {name: "Joe", age: 22, toString: function(){return this.name;}},
    {name: "Kevin", age: 24, toString: function(){return this.name;}},
    {name: "Peter", age: 21, toString: function(){return this.name;}}
];

var result = arr.join(", ");
//result = "Joe, Kevin, Peter"

2
これはかなり興味深いアプローチです。JSでこれができるとは思いませんでした。ただし、データはAPIから取得されているため、おそらく私のユースケースには適していませんが、それは間違いなく検討の糧です。
jackweirdy 2013年

4
あまり
乾燥

3
@BadHorsieいいえ、DRYではありません。もちろん、配列の外で単一の関数を定義toStringし、forループを使用して、この関数をすべての項目のメソッドに割り当てることもできます。または、コンストラクターのプロパティに1つのtoStringメソッドを追加することで、コンストラクター関数を処理するときにこのアプローチを使用できますprototype。ただし、この例は基本的な概念を示すためのものです。
basilikum 16

13

私もreduceメソッドを使用して遭遇しました、これはそれがどのように見えるかです:

[
  {name: "Joe", age: 22},
  {name: "Kevin", age: 24},
  {name: "Peter", age: 21}
].reduce(function (a, b) {return (a.name || a) + ", " + b.name})

(a.name || a)最初の要素が正しく処理されるが、残りは(ここにあるa文字列であり、そのためa.nameのオブジェクトとして扱われていない未定義です)。

編集:これをさらにこれにリファクタリングしました:

x.reduce(function(a, b) {return a + ["", ", "][+!!a.length] + b.name;}, "");

a常に文字列でbあり、常にオブジェクトであるので、私はこれがよりクリーンであると信じています(オプションのinitialValueパラメータをで使用しているためreduce

6か月後の編集:ああ、私は何を考えていましたか。"クリーナー"。私はコードGodsを怒らせました。


おかげで:D reducemap(姉妹の一種であることを考えると奇妙です)ほど広くサポートされていません。そのため、私はまだあなたの回答を使用しています:)
jackweirdy

6か月後の編集を見て、自分を雇わないことにしました。
jackweirdy 2013年

9

外部ライブラリを使用せずにそれを行う簡単な方法があるかどうかはわかりませんが、配列やコレクションなどを処理するためのたくさんのユーティリティがあるunderscore.jsは個人的に気に入ってい ます

アンダースコアを使用すると、1行のコードでこれを簡単に行うことができます。

_.pluck(arr, 'name').join(', ')


私は以前にアンダースコアを手を出しましたが、ネイティブJSでそれを行う方法を望んでいました
-1

arr当然、アレイはどこにありますか)
Ed Hinchliffe 2013年

けっこうだ!今ではどこでもアンダースコアを使用しているので、問題ありません。
Ed Hinchliffe 2013年


3

オブジェクト配列が変数によって参照されているとしましょう users

ES6を使用できる場合、最も簡単な解決策は次のとおりです。

users.map(user => user.name).join(', ');

そうでない場合は、lodashを使用できます。

 _.map(users, function(user) {
     return user.name;
 }).join(', ');

2

オブジェクトと動的キーの場合: "applications\":{\"1\":\"Element1\",\"2\":\"Element2\"}

Object.keys(myObject).map(function (key, index) {
    return myObject[key]
}).join(', ')

0

私が知っている古いスレッドですが、これに遭遇した人にはまだ非常に関連しています。

ここではArray.mapが提案されていますが、これは私がいつも使用している素晴らしいメソッドです。Array.reduceも言及されました...

このユースケースでは、個人的にArray.reduceを使用します。どうして?コードが少しクリーン/明確ではないにもかかわらず。マップ関数を結合にパイプするよりもはるかに効率的です。

これは、Array.mapが各要素をループして、配列内のオブジェクトの名前をすべて含む新しい配列を返す必要があるためです。次に、Array.joinは配列の内容をループして結合を実行します。

テンプレートリテラルを使用してコードを1行にまとめることで、jackweirdysの解答を減らし、読みやすさを向上させることができます。「すべての最新ブラウザでもサポートされています」

// a one line answer to this question using modern JavaScript
x.reduce((a, b) => `${a.name || a}, ${b.name}`);

0

確かではありませんが、これらはすべて機能しますが、2つのスキャンを実行しており、1つのスキャンでこれを実行できるため、最適ではありません。O(2n)はO(n)と見なされますが、常に真のO(n)を使用する方が適切です。

const Join = (arr, separator, prop) => {
    let combined = '';
    for (var i = 0; i < arr.length; i++) {
        combined = `${combined}${arr[i][prop]}`;
        if (i + 1 < arr.length)
            combined = `${combined}${separator} `;
    }
    return combined;
}

これは古い学校のように見えるかもしれませんが、このように考えることができます:

skuCombined = Join(option.SKUs, ',', 'SkuNum');

-1

これを試して

var x= [
  {name: "Joe", age: 22},
  {name: "Kevin", age: 24},
  {name: "Peter", age: 21}
]

function joinObj(a, attr) {
  var out = []; 
  for (var i=0; i<a.length; i++) {  
    out.push(a[i][attr]); 
  } 
 return out.join(", ");
}

var z = joinObj(x,'name');
z > "Joe, Kevin, Peter"
var y = joinObj(x,'age');
y > "22, 24, 21"

2
これは問題の関数と同じですが、name属性をハードコード化したために汎用性が低くなっています。(関数の引数を使用a[i].nameしませnameこれはと同等a[i]['name']です。)
nnnnnn
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.