Anahtarı JSON değeriyle değiştirin


106

Şu şekilde yapılandırılmış son derece büyük bir JSON nesnem var:

{A : 1, B : 2, C : 3, D : 4}

Nesnemdeki değerleri anahtarlarla değiştirebilen bir işleve ihtiyacım var ve bunu nasıl yapacağımı bilmiyorum. Bunun gibi bir çıktıya ihtiyacım olacak:

{1 : A, 2 : B, 3 : C, 4 : D}

Bunu yapabilmemin herhangi bir yolu var mı, manuel olarak her şeyin değiştirildiği yeni bir nesne oluşturabilir miyim?
Teşekkürler


1
tüm değerler sayı ve sayılar tekrar ediyor mu? Değerler tekrar ederse, değerlerini benzersiz bir değere değiştirmediğiniz sürece diğerlerinin üzerine yazacakları için onları değiştiremezsiniz. Daha iyi bir çözüm olabilir, takasa ihtiyaç duymanın nedeni nedir?
Patrick Evans

@PatrickEvans Hepsi sayılar ama tekrar etmiyorlar. Temel bir şifre yapmaya çalışıyorum.
2014

2
Bunun gibi bir "takas" işleminin [en az] iki nedenden dolayı sorunlu olduğunu belirtmek gerekir: 1) Değerler, anahtar haline geldiklerinde Dizelere dönüştürülür, bu nedenle beklenmedik "[nesne Nesnesi]" anahtarlarınız olduğunda şaşırmayın. Ve 2) yinelenen değerler (String'e dönüştürüldükten sonra) üzerine yazılır. En azından # 1, bir Nesne yerine bir Harita üreterek çözülebilir, bu nedenle:function swap(obj) {return new Map(Object.entries(x).map([k, v] => [v, k]))}
broofa

Yanıtlar:


118
function swap(json){
  var ret = {};
  for(var key in json){
    ret[json[key]] = key;
  }
  return ret;
}

Buradaki örnek FIDDLE sonuçları görmek için konsolunuzu açmayı unutmayın.


ES6 sürümleri:

static objectFlip(obj) {
  const ret = {};
  Object.keys(obj).forEach(key => {
    ret[obj[key]] = key;
  });
  return ret;
}

Veya Array.reduce () & Object.keys () kullanarak

static objectFlip(obj) {
  return Object.keys(obj).reduce((ret, key) => {
    ret[obj[key]] = key;
    return ret;
  }, {});
}

Veya Array.reduce () & Object.entries () kullanarak

static objectFlip(obj) {
  return Object.entries(obj).reduce((ret, entry) => {
    const [ key, value ] = entry;
    ret[ value ] = key;
    return ret;
  }, {});
}

44

lodash işlevini kullanabilirsiniz _.invert , ayrıca multivlaue kullanabilir

 var object = { 'a': 1, 'b': 2, 'c': 1 };

  _.invert(object);
  // => { '1': 'c', '2': 'b' }

  // with `multiValue`
  _.invert(object, true);
  // => { '1': ['a', 'c'], '2': ['b'] }

39

ES6 kullanımı:

const obj = { a: "aaa", b: "bbb", c: "ccc", d: "ddd" };
Object.assign({}, ...Object.entries(obj).map(([a,b]) => ({ [b]: a })))

2
Günümüz (2019) için daha iyi bir çözüm gibi görünüyor ! Biri doğrulayabilir, değil mi? Performans iyi mi? Anlambilim mükemmeldir: Bunun gerçekten basit bir "harita ve takas" çözümü olduğunu görebiliriz.
Peter Krauss

1
@ peter- krauss , Bir şeyi kaçırdığım takdirde jsben.ch/gHEtn ile ilgilenebilirsiniz , ancak bu cevap ile jPO'nun cevabı arasındaki rastgele bir karşılaştırma, jPO'nun for-loop'un grappeq'in harita yaklaşımından neredeyse 3'e 1 (en azından üzerinde benim tarayıcı).
Michael Hays

36

Nesnenin anahtarlarını alın ve ardından her bir anahtarın üzerinden geçmek ve değeri anahtar olarak ve anahtarı değer olarak ayarlamak için Array'ın azaltma işlevini kullanın.

const data = {
  A: 1,
  B: 2,
  C: 3,
  D: 4
}
const newData = Object.keys(data).reduce(function(obj, key) {
  obj[data[key]] = key;
  return obj;
}, {});
console.log(newData);


30

ES6 / ES2015 size kullanımını birleştirebilirsiniz Object.keys ve azaltmak yeniyi Object.assign fonksiyonu, bir ok fonksiyonu ve bilgisayarlı özellik adı oldukça basit bir tek deyim çözümü için.

const foo = { a: 1, b: 2, c: 3 };
const bar = Object.keys(foo)
    .reduce((obj, key) => Object.assign({}, obj, { [foo[key]]: key }), {});

Nesne yayma operatörünü kullanarak aktarıyorsanız (bunu yazarken aşama 3), bu işleri biraz daha basitleştirecektir.

const foo = { a: 1, b: 2, c: 3 };
const bar = Object.keys(foo)
    .reduce((obj, key) => ({ ...obj, [foo[key]]: key }), {});

Son olarak, Object.entries'iniz varsa (yazarken aşama 4), mantığı bir dokunuşla daha temizleyebilirsiniz (IMO).

const foo = { a: 1, b: 2, c: 3 };
const bar = Object.entries(foo)
    .reduce((obj, [key, value]) => ({ ...obj, [value]: key }), {});

Sözdizimi Hatası: /Users/markus/Entwicklung/IT1_Beleg/public/es6/vokabeltrainer.js: Beklenmeyen simge (53:45) 51 | eğer (btoa) {52 | girişler = Object.entries (girişler)> 53 | .reduce ((obj, [anahtar, değer]) => ({... obj, [değer]: anahtar}), {}); | ^
Superlokkus

@Superlokkus bu hata çıktısıyla ilgili en iyi yorumum, nesne yayılma sözdizimini çevirmediğiniz ve bugün itibariyle bunu yerel olarak destekleyen herhangi bir JavaScript motorunu bilmediğimdir.
joslarson

1
@ Grappeq'in çözümüne bakın, daha iyi görünüyor (en basit!).
Peter Krauss

16

Artık Object.fromEntries'e sahibiz:

obj => Object.fromEntries(Object.entries(obj).map(a => a.reverse()))

veya

obj => Object.fromEntries(Object.entries(obj).map(([k, v]) => ([v, k])))

Node.js sürüm 12'den itibaren nesne değişimi yapmanın standart bir yolu olmalıdır.
Hasarlı Organik

4

: @Joslarson ve @jPO cevapların tamamlayıcı olarak
ES6 gerekli olmadan, kullanabilirsiniz ve Virgül Operatörü :Object.keys Array.reduce

Object.keys(foo).reduce((obj, key) => (obj[foo[key]] = key, obj), {});

Bazıları bunu çirkin bulabilir, ancak her döngüdeki reducetüm özellikleri yaymadığı için "biraz" daha hızlıdır obj.


Yine de ... jPO'nun cevabı bunu neredeyse 2: 1 oranında geride bırakıyor. jsben.ch/R75aI ( Yorumunuzun çok uzun zaman öncesine ait olduğunu biliyorum, ancak grappeq'in cevabı üzerine yorum yapıyordum ve sizin örneğinizi de çalıştıracağımı düşündüm).
Michael Hays

Tamamen, bir for döngüsü forEach, mapveya reduceyöntemlerinden daha hızlı kalır . Bu cevabı es6'ya ihtiyaç duymadan tek astarlı bir çözüme sahip olmak ve yine de hız / etkinlik açısından alakalı olmak için yaptım.
Vaidd4

Haziran 2019 ve bu artık en son Google Chrome'da geçerli değil, fark artık neredeyse yok denecek kadar az (9:10)
Ivan Castellanos

Bu, ES6 varyantları arasında en iyi performans gösteren gibi görünüyor: jsben.ch/HvICq
Brian M. Hunt


2

ES6 kullanarak bulduğum en kısası ..

const original = {
 first: 1,
 second: 2,
 third: 3,
 fourth: 4,
};


const modified = Object
  .entries(original)
  .reduce((all, [key, value]) => ({ ...all, [value]: key }), {});

console.log('modified result:', modified);


1

Ramda Kullanımı :

const swapKeysWithValues = 
  R.pipe(
    R.keys,
    R.reduce((obj, k) => R.assoc(source[k], k, obj), {})
  );

const result = swapKeysWithValues(source);

1

Bu görevi bir npm modülü kullanarak yapmanın daha iyi olduğuna inanıyorum invert-kv.

invert-kv : Bir nesnenin anahtar / değerini ters çevirir. Örnek: {foo: 'bar'} → {bar: 'foo'}

https://www.npmjs.com/package/invert-kv

const invertKv = require('invert-kv');

invertKv({foo: 'bar', unicorn: 'rainbow'});
//=> {bar: 'foo', rainbow: 'unicorn'}

1
Neden başka bir kitaplık, @ Sc0ttyD'nin önerdiği gibi tek satırlık bir çözümden veya hatta basit bir for döngüsünden daha iyi kullanılıyor?
Arel

1

Saf ve anlamsız bir tarzda saf Ramda ile:

const swapKeysAndValues = R.pipe(
   R.toPairs,
   R.map(R.reverse),
   R.fromPairs,
);

Veya biraz daha kıvrımlı ES6 versiyonuyla, hala tamamen işlevsel:

const swapKeysAndValues2 = obj => Object
    .entries(obj)
    .reduce((newObj, [key, value]) => ({...newObj, [value]: key}), {})

0
    var data = {A : 1, B : 2, C : 3, D : 4}
    var newData = {};
    Object.keys(data).forEach(function(key){newData[data[key]]=key});
    console.log(newData);

3
Bu objectnereden geliyor?
Maxime Launois

ve mapyapmanız gereken bu değil , onu burada kullanıyorsunuzforEach
barbsan

Asla her biri için kullanmadım. Altçizgi.js'nin her işlevini kullanıyorum, bu yüzden forEach hakkında bir şey bilmiyordum. Teşekkürler @barbsan
Anup Agarwal

0

İşte çevirmenin keysve valuesES6'da tamamen işlevsel bir uygulaması :

TypeScript

  const flipKeyValues = (originalObj: {[key: string]: string}): {[key: string]: string} => {
    if(typeof originalObj === "object" && originalObj !== null ) {
      return Object
      .entries(originalObj)
      .reduce((
        acc: {[key: string]: string}, 
        [key, value]: [string, string],
      ) => {
        acc[value] = key
        return acc;
      }, {})
    } else {
      return {};
    }
  }

JavaScript

const flipKeyValues = (originalObj) => {
    if(typeof originalObj === "object" && originalObj !== null ) {
        return Object
        .entries(originalObj)
        .reduce((acc, [key, value]) => {
          acc[value] = key
          return acc;
        }, {})
    } else {
        return {};
    }
}

const obj = {foo: 'bar'}
console.log("ORIGINAL: ", obj)
console.log("FLIPPED: ", flipKeyValues(obj))


0
function swapKV(obj) {
  const entrySet = Object.entries(obj);
  const reversed = entrySet.map(([k, v])=>[v, k]);
  const result = Object.fromEntries(reversed);
  return result;
}

Bu, nesnenizi {A : 1, B : 2, C : 3, D : 4}dizi benzeri yapabilir, böylece sahip olabilirsiniz

const o = {A : 1, B : 2, C : 3, D : 4}
const arrayLike = swapKV(o);
arrayLike.length = 5;
const array = Array.from(arrayLike);
array.shift(); // undefined
array; // ["A", "B", "C", "D"]

0

Burada, anahtarları değerlerle değiştirecek ancak yinelenenleri kaybetmeyecek bir seçenek, eğer nesneniz: {a: 1, b: 2, c: 2} ise, çıktıda her zaman bir dizi döndürür:

function swapMap(map) {
    const invertedMap = {};
    for (const key in map) {
        const value = map[key];
        invertedMap[value] = invertedMap[value] || [];
        invertedMap[value].push(key);
    }
    return invertedMap;
}
swapMap({a: "1", b: "2", c: "2"})
// Returns => {"1": ["a"], "2":["b", "c"]}
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.