首页 > 解决方案 > 如何打乱一个数组,在同一对象属性之间提供最大空间?

问题描述

例如,我有一个数组:

[{name: "foo"},{name: "foo"}, {name: "foo"}, {name: "bar"}, {name: "bar"}, {name: "qux"}, {name: "corge"}, {name: "grault"}]

它需要保持相同元素之间的最佳距离,它确实需要始终保持相同的距离,但尽可能远

[{name: "foo"},{name: "bar"},{name: "qux"},{name: "foo"},{name: "corge"},{name: "grault"},{name: "foo"},{name: "bar"}]

尝试:

var _ = _.noConflict();

let data = [
  {
    competitor: "Patrícia Gregório"
  },
  {
    competitor: "Patrícia Gregório"
  },
  {
    competitor: "Erika Eleuterio Salim Ali"
  },
  {
    competitor: "Mariani aparecida da Silva"
  },
  {
    competitor: "NATALIA TELLES SCHMIDT"
  },
  {
    competitor: "Tamila Cavalcante Castilho"
  },
  {
    competitor: "Heloísa Brasil dos Santos"
  },
  {
    competitor: "Rafaele Caraça"
  },
  {
    competitor: "Luana Aparecida"
  },
  {
    competitor: "Camila Vieira Carvalho de Souza"
  },
  {
    competitor: "Kemylli Quarties"
  },
  {
    competitor: "Amanda Polli"
  },
  {
    competitor: "Carolina Marques Figueiredo"
  },
  {
    competitor: "Marcelle Conceição Pereira Longo"
  },
  {
    competitor: "MICAELLA FERNANDES FRANÇA DA SILVA"
  },
  {
    competitor: "Liv landin"
  },
  {
    competitor: "Maria Eduarda Rossi Krieck"
  },
  {
    competitor: "Isabella Guimarães Pinto Costa"
  },
  {
    competitor: "Alessandra Esposito de Castro Cardoso"
  },
  {
    competitor: "FERNANDA FERNANDES DE CARVALHO"
  },
  {
    competitor: "Maria Eduarda Miranda"
  },
  {
    competitor: "Beatriz Macedo"
  },
  {
    competitor: "CARLA AMANDA DE OLIVEIRA"
  },
  {
    competitor: "eduarda cavalcante"
  },
  {
    competitor: "Amanda Chítero Silva"
  },
  {
    competitor: "Livia Rodrigues Lopes"
  },
  {
    competitor: "Priscila Sequeira"
  },
  {
    competitor: "Keila Pacheco"
  },
  {
    competitor: "Damaris Trindade"
  },
  {
    competitor: "Priscila Sequeira"
  },
  {
    competitor: "Fabiana Fernandes"
  },
  {
    competitor: "Carolina lois soares de Arruda"
  },
  {
    competitor: "Pollyanna Guratti"
  },
  {
    competitor: "Bruna Vieira"
  },
  {
    competitor: "Beatriz Delgado de Oliveira"
  },
  {
    competitor: "KELLY MOREIRA"
  },
  {
    competitor: "Fernanda Suzuki de Carvalho"
  },
  {
    competitor: "Keila Pacheco"
  },
  {
    competitor: "Mariana Moreira de Oliveira"
  },
  {
    competitor: "Angelita da Silva Rezende Vieira"
  },
  {
    competitor: "Rogéria da Silva Rezende"
  },
  {
    competitor: "Anna Laura Rodrigues dos Santos"
  },
  {
    competitor: "Maria Heloysa Xavier dos Santos"
  },
  {
    competitor: "Vanessa Gonçalves"
  },
  {
    competitor: "CARMEM SOARES FONSECA CAETANO"
  },
  {
    competitor: "DEBORA GAMA LIMA"
  },
  {
    competitor: "DARLENE DINIZ"
  },
  {
    competitor: "VITORIA PASCOAL DE SOUSA SANTOS"
  },
  {
    competitor: "GLAYCIE EVELYN MENDONÇA"
  },
  {
    competitor: "MARIANA MENEZES"
  },
  {
    competitor: "Julia Carvalho"
  },
  {
    competitor: "Isabela Tidioli"
  },
  {
    competitor: "PIETRA MACIEL"
  },
  {
    competitor: "Ana Simões"
  },
  {
    competitor: "PIETRA MACIEL"
  },
  {
    competitor: "Priscila Sequeira"
  },
  {
    competitor: "Jéssica Rosa"
  },
  {
    competitor: "Patrícia Gregório"
  },
  {
    competitor: "Patrícia Gregório"
  },
  {
    competitor: "Erika Eleuterio Salim Ali"
  },
  {
    competitor: "Mariani aparecida da Silva"
  },
  {
    competitor: "NATALIA TELLES SCHMIDT"
  },
  {
    competitor: "Tamila Cavalcante Castilho"
  },
  {
    competitor: "Heloísa Brasil dos Santos"
  },
  {
    competitor: "Rafaele Caraça"
  },
  {
    competitor: "Luana Aparecida"
  },
  {
    competitor: "Camila Vieira Carvalho de Souza"
  },
  {
    competitor: "Kemylli Quarties"
  },
  {
    competitor: "Amanda Polli"
  },
  {
    competitor: "Carolina Marques Figueiredo"
  },
  {
    competitor: "Marcelle Conceição Pereira Longo"
  },
  {
    competitor: "MICAELLA FERNANDES FRANÇA DA SILVA"
  },
  {
    competitor: "Liv landin"
  },
  {
    competitor: "Maria Eduarda Rossi Krieck"
  },
  {
    competitor: "Isabella Guimarães Pinto Costa"
  },
  {
    competitor: "Alessandra Esposito de Castro Cardoso"
  },
  {
    competitor: "FERNANDA FERNANDES DE CARVALHO"
  },
  {
    competitor: "Maria Eduarda Miranda"
  },
  {
    competitor: "Beatriz Macedo"
  },
  {
    competitor: "CARLA AMANDA DE OLIVEIRA"
  },
  {
    competitor: "eduarda cavalcante"
  },
  {
    competitor: "Amanda Chítero Silva"
  },
  {
    competitor: "Livia Rodrigues Lopes"
  },
  {
    competitor: "Priscila Sequeira"
  },
  {
    competitor: "Keila Pacheco"
  },
  {
    competitor: "Damaris Trindade"
  },
  {
    competitor: "Priscila Sequeira"
  },
  {
    competitor: "Fabiana Fernandes"
  },
  {
    competitor: "Carolina lois soares de Arruda"
  },
  {
    competitor: "Pollyanna Guratti"
  },
  {
    competitor: "Bruna Vieira"
  },
  {
    competitor: "Beatriz Delgado de Oliveira"
  },
  {
    competitor: "KELLY MOREIRA"
  },
  {
    competitor: "Fernanda Suzuki de Carvalho"
  },
  {
    competitor: "Keila Pacheco"
  },
  {
    competitor: "Mariana Moreira de Oliveira"
  },
  {
    competitor: "Angelita da Silva Rezende Vieira"
  },
  {
    competitor: "Rogéria da Silva Rezende"
  },
  {
    competitor: "Anna Laura Rodrigues dos Santos"
  },
  {
    competitor: "Maria Heloysa Xavier dos Santos"
  },
  {
    competitor: "Vanessa Gonçalves"
  },
  {
    competitor: "CARMEM SOARES FONSECA CAETANO"
  },
  {
    competitor: "DEBORA GAMA LIMA"
  },
  {
    competitor: "DARLENE DINIZ"
  },
  {
    competitor: "VITORIA PASCOAL DE SOUSA SANTOS"
  },
  {
    competitor: "GLAYCIE EVELYN MENDONÇA"
  },
  {
    competitor: "MARIANA MENEZES"
  },
  {
    competitor: "Julia Carvalho"
  },
  {
    competitor: "Isabela Tidioli"
  },
  {
    competitor: "PIETRA MACIEL"
  },
  {
    competitor: "Ana Simões"
  },
  {
    competitor: "PIETRA MACIEL"
  },
  {
    competitor: "Priscila Sequeira"
  },
  {
    competitor: "Jéssica Rosa"
  }
];


const spreadOrder = (array) => {
  var temp = [],
    count = {};

  for (let v of array) {
    if (!count[v.competitor]) count[v.competitor] = 0;
    if (!temp[count[v.competitor]]) temp[count[v.competitor]] = [];
    temp[count[v.competitor]].push(v);
    count[v.competitor]++;
  }
  let biggestCount = 0;
  let sorted = _.flatMap(temp, (array) =>
    array.sort((a, b) => {
      if (Math.abs(count[a.competitor] - count[b.competitor]) > biggestCount)
        biggestCount =
          count[b.competitor] > biggestCount
            ? count[b.competitor]
            : biggestCount;
      return count[b.competitor] - count[a.competitor];
    })
  );

  sortedCompare = JSON.parse(JSON.stringify(sorted));

  if (biggestCount > 1) {
    let ofCounter = 0;

    for (let i = sorted.length - biggestCount; i < sorted.length; i++) {
      let newIndex = Math.floor(Math.random() * (i - 1));
      const sortedNow =
        sortedCompare[newIndex].competitor == sortedCompare[i].competitor;
      let sortedBefore = false;
      if (newIndex > 0)
        sortedBefore =
          sortedCompare[newIndex - 1].competitor == sortedCompare[i].competitor;

      const sortedAfter =
        sortedCompare[newIndex + 1].competitor == sortedCompare[i].competitor;
      if (
        (sortedNow || sortedBefore || sortedAfter) &&
        ofCounter <= sorted.length
      ) {
        i--;
        ofCounter++;
      } else {
        let changedContent = sorted[newIndex];
        sorted[newIndex] = sorted[i];
        sorted[i] = changedContent;
        let changedContentCompare = sortedCompare[newIndex];
        sortedCompare[newIndex] = sortedCompare[i];
        sortedCompare[i] = changedContentCompare;

        sortedCompare = JSON.parse(JSON.stringify(sorted));
      }
    }
  }

  return sorted;
};

const shuffle = (array) => {
  let currentIndex = array.length,
    temporaryValue,
    randomIndex;

  // While there remain elements to shuffle...
  while (0 !== currentIndex) {
    // Pick a remaining element...
    randomIndex = Math.floor(Math.random() * currentIndex);
    currentIndex -= 1;

    // And swap it with the current element.
    temporaryValue = array[currentIndex];
    array[currentIndex] = array[randomIndex];
    array[randomIndex] = temporaryValue;
  }

  return array;
};

const spreadOrder2 = (array) => {
  var temp = [],
    count = {};

  for (let v of array) {
    if (!count[v.competitor]) count[v.competitor] = 0;
    if (!temp[count[v.competitor]]) temp[count[v.competitor]] = [];
    temp[count[v.competitor]].push(v);
    count[v.competitor]++;
  }

  for (let i = 1; i < temp.length; i++) {
    if (temp[i].length > 3) {
      const lastComp = temp[i - 1][temp[i - 1].length - 1];
      for (let j = 0; j < 2; j++) {
        if (lastComp.competitor === temp[i][j].competitor) spreadOrder2(array);
      }
    }
  }

  const flat = temp.flat();

  return flat;
};

const newTry = (array) => {
  for (let i = 2; i < array.length - 1; i++) {
    if (array[i - 2].competitor._id == array[i].competitor._id) {
      let buffer = array[i + 1];
      array[i + 1] = array[i];
      array[i] = buffer;
    } else if (array[i - 1].competitor._id == array[i].competitor._id) {
      let buffer = array[i + 1];
      array[i + 1] = array[i];
      array[i] = buffer;
    }
  }
  for (let i = array.length - 3; i > 0; i--) {
    if (array[i + 2].competitor._id == array[i].competitor._id) {
      let buffer = array[i - 1];
      array[i - 1] = array[i];
      array[i] = buffer;
    } else if (array[i + 1].competitor._id == array[i].competitor._id) {
      let buffer = array[i - 1];
      array[i - 1] = array[i];
      array[i] = buffer;
    }
  }
  return array;
};

Array.prototype.unique = function () {
  var i = 0,
    t = 1,
    l = (this.length >>> 0) - 1;
  for (; i < l; t = ++i + 1)
    while ((t = this.indexOf(this[i], t)) !== -1) this.splice(t, 1);
  return this;
};
Array.prototype.count = function (item) {
  var i = 0,
    t = 0;
  while ((i = this.indexOf(item, i) + 1)) t++;
  return t;
};
Array.prototype.remove = function (item) {
  var i = this.indexOf(item);
  if (i !== -1) this.splice(i, 1);
  return this;
};

function shuffleArray(array, previous) {
  if (!array.length) return array;
  // The list of unique items in the array
  var univals = array.slice().unique(),
    idx,
    pivot,
    rest;
  if (previous != null)
    // The array can't start with the previous element
    univals.remove(previous);

  while (univals.length) {
    // We choose an element from the possible ones
    idx = Math.floor(Math.random() * univals.length);
    pivot = univals[idx];
    // We try to shuffle the rest of the array.
    rest = shuffleArray(array.slice().remove(pivot), pivot);
    // If we got a shuffled array, we're done.
    // Else, we remove our pivot element from the possible ones
    if (rest != null) return [pivot].concat(rest);
    else univals.splice(idx, 1);
  }
  return null;
}

function insertNextItem(list, item) {
  // special case an empty items array
  if (list.length === 0) {
    list.push(item);
    return true;
  }

  // build an array of possible insertion positions
  // items.length + 1 means to add it at the end
  var possiblePositions = [];
  for (var i = 0; i < list.length + 1; i++) {
    possiblePositions.push(i);
  }

  // select random position, see if that is allowed
  // if not, remove it from the possibilities and select a new random position
  while (possiblePositions.length > 0) {
    var randIndex = Math.floor(Math.random() * possiblePositions.length);
    var pos = possiblePositions[randIndex];
    // check if this position is allowed
    if (list[pos] !== item && (pos === 0 || list[pos - 1] !== item)) {
      // position is allowed, insert it and return
      list.splice(pos, 0, item);
      return true;
    } else {
      // was not allowed, so remove this possiblePositions choice
      // and let the loop try again
      possiblePositions.splice(randIndex, 1);
    }
  }
  return false;
}

function buildList(sourceItems, num) {
  var items = [];
  for (var i = 0; i < num; i++) {
    insertNextItem(
      items,
      sourceOfItems[Math.floor(Math.random() * sourceOfItems.length)]
    );
  }
  return items;
}


// Testing
console.log(data.map((x) => x.competitor));
let countAll = 0;
// testing 1000 times
for(let i = 0; i < 1000; i++) {
data = shuffle(data);
data = spreadOrder(data);
// counting repeated value
const count = data.filter((obj, index) =>
data[index - 1] != null ? obj.competitor === data[index - 1].competitor : false).length;
// if repeated value, add 1 to countAll
if(count > 0) countAll++;
}
// show how many tests has repeated values closest to 0 is better 
console.log(countAll);
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.20/lodash.min.js"></script>

它不能是这样的:

 [{name: "foo"}, {name: "bar"}, {name: "qux"}, {name: "corge"}, {name: "grault"},{name: "foo"}, {name: "bar"}, {name: "foo"}]

这个错误的例子是在数组末尾重复重复的名称,如果可能,它需要保持至少 2 个元素的距离

标签: javascriptarrayssorting

解决方案


推荐阅读