javascript - 如何打乱一个数组,在同一对象属性之间提供最大空间?
问题描述
例如,我有一个数组:
[{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 个元素的距离
解决方案
推荐阅读
- php - 在php单元测试中的“DataProvider”方法中从“setUpBeforeClass”访问静态变量
- amazon-web-services - 哪些资源正在使用弹性 IP?
- asp.net - 如何在重写规则中匹配一个匹配 URL 中的两个条件?
- mysql - 用于分组图像的 MySQL 解决方案?
- highcharts - 无法以角度 6 呈现图表
- javascript - 500 内部服务器错误 ajax datatables codeigniter(数据库查询)
- javascript - 使用 JavaScript 的简单堆栈效果
- perl - Perl 中的逻辑运算符或赋值不起作用?
- git - ssh:连接到主机 xxx.yzaaa 端口 22:连接被拒绝
- django - django 后端不支持绝对路径