0

I have an array

var array = [{
  "Abigail": ["I feel that anyone breaking the law deserves what they get", "1"],
  "Alexandra": ["There comes a time that you can just", "5"],
  "Alexis": ["She looks mean anyways.", "2"]
}, {
  "Abigail": ["Bet she wishes she hadn't broken the law", "1"],
  "Alexandra": ["Bad girls don't wear scarfs.", "5"],
  "Alexis": ["That's the look of someone who has lost hope in humanity.", "5"]
}, {
  "Abigail": ["She probably wanted this to happen.", "1"],
  "Alexandra": ["What did she do to warrent all of this attention?", "5"],
  "Alexis": ["I think people just going about it all wrong.", "5"]
}]

I would like to shuffle just the names within the array, but want to keep the order of the name the same.

I tried a bunch of things including this code of the Fisher- Yates Shuffle https://bost.ocks.org/mike/shuffle/. I can only shuffle within the lower level lists but not the names.

Example of a desired outcome:

var arrayShuffled = [{
  "Abigail": ["I feel that anyone breaking the law deserves what they get", "1"],
  "Alexis": ["She looks mean anyways.", "2"],
  "Alexandra": ["There comes a time that you can just stop screaming in peoples ears.", "5"]
}, {
  "Abigail": ["Bet she wishes she hadn't broken the law", "1"],
  "Alexis": ["That's the look of someone who has lost hope in humanity.", "5"],
  "Alexandra": ["Bad girls don't wear scarfs.", "5"]
}, {
  "Abigail": ["She probably wanted this to happen.", "1"],
  "Alexis": ["I think people just going about it all wrong.", "5"],
  "Alexandra": ["What did she do to warrent all of this attention?", "5"]
}]
Mr. Polywhirl
  • 42,981
  • 12
  • 84
  • 132
chagag
  • 65
  • 5
  • 2
    I don't think object keys have any guaranteed order in JavaScript. Maybe you need a `Map`? https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map – grooveplex Jan 26 '19 at 00:38
  • 2
    there is no shuffling in your example. you are changing the order of object properties which are not inherently ordered. – derelict Jan 26 '19 at 00:38
  • @grooveplex They do, in ES6 and above. – CertainPerformance Jan 26 '19 at 00:42
  • As of ECMAScript 2015 (ES6), object properties do have an order (they didn't before): http://www.ecma-international.org/ecma-262/6.0/index.html#sec-ordinary-object-internal-methods-and-internal-slots-ownpropertykeys – Laurens Jan 26 '19 at 00:52

3 Answers3

1

Start by randomizing the keys of one of the rows and then recreate all the rows with those keys:

var a = [{
  "Abigail": ["I feel that anyone breaking the law deserves what they get", "1"],
  "Alexandra": ["There comes a time that you can just", "5"],
  "Alexis": ["She looks mean anyways.", "2"]
}, {
  "Abigail": ["Bet she wishes she hadn't broken the law", "1"],
  "Alexandra": ["Bad girls don't wear scarfs.", "5"],
  "Alexis": ["That's the look of someone who has lost hope in humanity.", "5"]
}, {
  "Abigail": ["She probably wanted this to happen.", "1"],
  "Alexandra": ["What did she do to warrent all of this attention?", "5"],
  "Alexis": ["I think people just going about it all wrong.", "5"]
}]

var keys = Object.keys(a[0]);
keys.sort(function(a, b) {
  return Math.random() - 0.5;
});

var a_shuffled = [];
for (var i = 0; i < a.length; i++) {
  a_shuffled[i] = {}
  keys.forEach(function(k) {
    a_shuffled[i][k] = a[i][k]
  });
}
console.log(a_shuffled);
.as-console-wrapper { top: 0; max-height: 100% !important; }
Mr. Polywhirl
  • 42,981
  • 12
  • 84
  • 132
Laurens
  • 2,596
  • 11
  • 21
  • This is not how you shuffle an array. – xehpuk Jan 26 '19 at 00:55
  • @xehpuk he doesn't want to shuffle an array, he wants to shuffle an object and keep the same random shuffle for all objects in an array.. – Laurens Jan 26 '19 at 01:01
  • `keys` is an array. You are calling `sort` on it to supposedly shuffle it. – xehpuk Jan 26 '19 at 01:05
  • No need to use an external site like JSFiddle if you can embed the script in the post. – Mr. Polywhirl Jan 26 '19 at 01:16
  • @xehpuk. Sort works totally fine to shuffle an array. You could implement the modern version of the Fisher–Yates shuffle algorithm to optimize the shuffle if you need better performance. – Laurens Jan 26 '19 at 01:27
  • No, it doesn't. The elements aren't uniformly distributed: https://stackoverflow.com/a/18650169/1178016 – xehpuk Jan 26 '19 at 01:40
  • @xehpuk Interesting. See Mr. Polywhirl answer for a similar approach with a better shuffle algorithm that is uniformly distributed. – Laurens Jan 26 '19 at 09:45
  • Thanks to everyone for this fascinating discussion. I really appreciate it! – chagag Jan 26 '19 at 22:07
1

Not that much different that Laurens', but it implements a Knuth (or Fisher-Yates) shuffle on the keys. I also used ES6 syntax.

var objList = [{
  "Abigail": ["I feel that anyone breaking the law deserves what they get", "1"],
  "Alexandra": ["There comes a time that you can just", "5"],
  "Alexis": ["She looks mean anyways.", "2"]
}, {
  "Abigail": ["Bet she wishes she hadn't broken the law", "1"],
  "Alexandra": ["Bad girls don't wear scarfs.", "5"],
  "Alexis": ["That's the look of someone who has lost hope in humanity.", "5"]
}, {
  "Abigail": ["She probably wanted this to happen.", "1"],
  "Alexandra": ["What did she do to warrent all of this attention?", "5"],
  "Alexis": ["I think people just going about it all wrong.", "5"]
}]

console.log(shuffleArrayItemKeys(objList)) // Print the shuffled list.

function shuffleArrayItemKeys(arr) {
  var keys = knuthShuffle(Object.keys(arr[0]))
  return arr.map((item) => {
    return keys.reduce((result, key, index) => {
      return { ... result, ... { [key] : item[key] } }
    }, {})
  })
}

function knuthShuffle(arr) {
  var currIndex = arr.length, randIndex
  while (currIndex !== 0) {
    randIndex = Math.floor(Math.random() * currIndex)
    currIndex--
    __swap__(arr, currIndex, randIndex)
  }
  return arr
}

/**
 * @private
 */
function __swap__(arr, index1, index2) {
  let tmp = arr[index1]
  arr[index1] = arr[index2]
  arr[index2] = tmp
}
.as-console-wrapper {
  top: 0;
  max-height: 100% !important;
}

Note: Using Object.assign(result, { [key] : item[key] }) can be used in-place of the spread operator e.g. { ... result, ... { [key] : item[key] } } as a more browser-friendly alternative.

Mr. Polywhirl
  • 42,981
  • 12
  • 84
  • 132
  • 1
    Great improvement! As it turns out my shuffle is not uniformly distributed, so this approach is better – Laurens Jan 26 '19 at 09:47
0

Objects in JavaScript have no particularly defined order for their entries. If I were to create an array that looks like [1,3,5,7,9], these elements are not ordered by their keys, they're ordered by their values. This array would be equivalent to defining an object

let arr = [1,3,5,7,9];
let obj = {
    0: 1, 
    1: 3, 
    2: 5,
    3: 7,
    4: 9
};

The difference between the two is that Array is an Object, but an Object is not an Array.

arr instanceof Object //true
arr instanceof Array  //true
obj instanceof Object //true
obj instanceof Array  //false

Since keys are natural order in JavaScript, you can't shuffle the actual elements of an object. If I were to shuffle that array, the keys wouldn't be changing order, just the values associated with each key.

If you wanted to achieve what you're doing, you'd need to restructure your data. What you'd need to do is create is such that

var array = [
    [
        {"Abigail":["...", "1"]},
        {"Alexandra": ["...", "5"]},
        {"Alexis": ["...", "2"]}
    ], [//...
    ]
];

And now defined like this, they exist inside an array, so they can be shuffled around - you'd just need to change the way you're accessing things since they're now bound by index and not a defined key.

nixin72
  • 322
  • 4
  • 16
  • Not completely true: As of ECMAScript 2015 (ES6), object properties do have an order (they didn't before): http://www.ecma-international.org/ecma-262/6.0/index.html#sec-ordinary-object-internal-methods-and-internal-slots-ownpropertykeys – Laurens Jan 26 '19 at 01:24
  • Okay, interesting... I see, when you call `Object.keys(obj)` it will return an array of all the keys in their defined and not natural order. So an object's keys are stored in an internal array, thus ordering the keys, while the actual object is likely created behind the scenes using a HashMap or something. But the ordering is preserved nonetheless. – nixin72 Jan 26 '19 at 01:54