1D -> 2D Array W / Нормальная кривая Длина подмассива - PullRequest
2 голосов
/ 02 мая 2019

Я пытаюсь разбить одномерный массив на двумерный, где под-массивы имеют разную длину. Эта дисперсия должна следовать гауссовой кривой [или форме насыпи]. Итак, скажем, переменная 2D-массива называется gaussianCurve. Массив в gaussianCurve [0] & gaussianCurve [n] будет иметь длину 1, а gaussianCurve [n / 2] будет максимумом, предоставленным параметром "maxArrayLength". Это заставляет число индексов gaussianCurve стать переменными.

Скажите, что у меня есть следующий псевдо-код:

function (oneDimentionalArray, maxArrayLength) {
// oneDimentionalArray is ["A","B","C","D","E","F","G","H","I","J","K"]
// maxArrayLength is 5
// Currently working like this (i.e. "batches"):
// return [["A","B","C","D","E"],["F","G","H","I","J"],["K"]]
// would LIKE it to work like this
    gaussianCurve = []
    gaussianCurve.push(["A"])
    gaussianCurve.push(["B", "C"])
    gaussianCurve.push(["D", "E", "F", "G", "H"])
    gaussianCurve.push(["I", "J"])
    gaussianCurve.push(["K"])

    return  gaussianCurve
}

Зачем мне такая вещь? Прогресс-бары.

  1. Они не показывают, что я делаю успехи немедленно
    1. Это связано с тем, что первое задание должно быть выполнено до того, как планка сможет двигаться
  2. Они замедляются на 95% +, а иногда даже держатся на 100%
    1. Просто раздражает

Любые предложения приветствуются. Я просто не вижу ответа в уме.

РЕДАКТИРОВАТЬ: я чувствую, что это было плохо сформулировано, поэтому я переписываю его.

... gaussianCurve [0] .length & gaussianCurve [gaussianCurve.length - 1] .length будет 1, а gaussianCurve [gaussianCurve.length / 2] .length будет до "maxArrayLength".

ВХОД:

function gaussianRefactor(["A","B","C","D","E","F","G","H","I","J","K"], 1)
function gaussianRefactor(["A","B","C","D","E","F","G","H","I","J","K"], 2)
function gaussianRefactor(["A","B","C","D","E","F","G","H","I","J","K"], 4)
function gaussianRefactor(["A","B","C","D","E","F","G","H","I","J","K"], 8)
function gaussianRefactor(["A","B","C","D","E","F","G","H","I","J","K"], 16)

ВЫВОД:

[["A"],["B"],["C"],["D"],["E"],["F"],["G"],["H"],["I"],["J"],["K"]]
[["A"],["B","C"],["D","E"],["F","G"],["H","I"],["J"],["K"]]
[["A"],["B","C","D"],["E","F","G","H"],["I","J","K"]]
[["A"],["B","C","D","E","F","G","H","I"],["J","K"]]
[["A","B","C","D","E","F","G","H","I","J","K"]]

Никакой внутренний массив не может превышать длину maxArrayLength

Ответы [ 3 ]

2 голосов
/ 05 мая 2019

Я быстро сделал снимок, и это похоже на работу. Некоторые потенциальные улучшения:

  • Проверка ввода для функций
  • Помещает любые возможные оставшиеся значения в средний бункер. Для четных полных корзин выиграет некоторая балансировка. После этого может быть полезно попытаться отсортировать каждую ячейку на основе исходного индекса во входных данных, так как сейчас все может закончиться не по порядку. Но если это просто наличие нелинейно распределенных заданий для индикатора выполнения, порядок может не иметь значения.

function probability(s, m, x) {
	var eExp = -Math.pow(x - m, 2) /
		(2 * Math.pow(s, 2));
	return 1/(Math.sqrt(2*Math.PI) * s) *
		Math.pow(Math.E, eExp);
}

function gassianArray(input, nBins) {
	// first try to determine a reasonable value of s so that the outer bins have a value
	var s = 0.1;
	var sMax = 10;
	var m = (nBins - 1) / 2.0;
	var outerBinMinimum = 1 / input.length;
	var p = 0;
	while (true && s <= sMax) {
		p = probability(s, m, 0);
		if (p >= outerBinMinimum) {
			break;
		} else {
			s += 0.1;
		}
	}

	// holds arrays
	var output = [];
	// holds desired array sizes
	var outputLengths = [];
	// fill these based on probability density
	for (var b=0; b<nBins; b++) {
		var n = Math.floor(probability(s, m, b) * input.length);
		output.push([]);
		outputLengths.push(n);
	}

	// fill arrays from outside, leaving extra values for the middle
	var midIndex = Math.floor(m);
	// left side
	for (var i=0; i<midIndex; i++) {
		for (var j=0; j<outputLengths[i]; j++) {
			output[i].push(input.shift());
		}
	}
	// right side
	for (var i=nBins-1; i>=midIndex; i--) {
		for (var j=0; j<outputLengths[i]; j++) {
			output[i].push(input.pop());
		}
		output[i].reverse();
	}
	// whatever remains goes in the "middle"
	while (input.length !== 0) {
		output[midIndex].unshift(input.pop());
	}

	return output;
}

var input = ["A","B","C","D","E","F","G","H","I","J","K"];
var n = 5;
console.log(gassianArray(input, n));
/*
[ [ 'A' ],
  [ 'B', 'C' ],
  [ 'E', 'D', 'F', 'G', 'H' ],
  [ 'I', 'J' ],
  [ 'K' ] ]
*/


var input = ["A","B","C","D","E","F","G","H","I","J","K","L","M","N","O","P","Q","R","S","T","U","V","W","X","Y","Z"];
var n = 6;
console.log(gassianArray(input, n));
/*
[ [ 'A' ],
  [ 'B', 'C', 'D', 'E' ],
  [ 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N' ],
  [ 'O', 'P', 'Q', 'R', 'S', 'T', 'U' ],
  [ 'V', 'W', 'X', 'Y' ],
  [ 'Z' ] ]
*/
1 голос
/ 12 мая 2019

Очень интересный вызов.:)

Я немного поиграл, и вот что я придумал:

function chunk(arr, start, n) {
  if (arr.length < n) {
    return null;
  }

  return arr.splice(start, n);
}

function gaussianArray(arr, max) {
  const len = arr.length;

  if (max > len) {
    return [arr];
  }

  const curve = [];

  // Extract middle.
  const mid = Math.floor(len / 2);
  const startIndex = mid - (max / 2) + 1;
  const highest = arr.splice(startIndex, max);

  curve.push(highest);

  // Splits the rest in 2 arrays; left side and right side, middle already excluded.
  const leftArr = arr.slice(0, startIndex);
  const rightArr = arr.slice(startIndex, len);

  let leftMax = max;
  let rightMax = max;

  // Adds chunks from left side.
  while (leftArr.length) {
    const leftChunk = chunk(leftArr, leftArr.length - leftMax, leftMax);

    if (leftChunk) {
      curve.unshift(leftChunk);
    } else {
      leftMax--;
    }
  }

  // Adds chunks from right side.
  while (rightArr.length) {
    const rightChunk = chunk(rightArr, 0, rightMax);

    if (rightChunk) {
      curve.push(rightChunk);
    } else {
      rightMax--;
    }
  }

  return curve;
}

console.log(JSON.stringify(gaussianArray(["A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K"], 1)));
console.log(JSON.stringify(gaussianArray(["A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K"], 2)));
console.log(JSON.stringify(gaussianArray(["A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K"], 4)));
console.log(JSON.stringify(gaussianArray(["A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K"], 8)));
console.log(JSON.stringify(gaussianArray(["A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K"], 16)));

Это не совсем то, что вы хотите, но я думаю, что это должно быть близко к решению вашей проблемы с индикатором прогресса ...

0 голосов
/ 25 мая 2019

Это больше соответствовало тому, что я думал. Мне очень не нравится, как я нахожу сигму. Я знаю, что мне нужно просто изменить формулу, чтобы вычислить ее, но мне еще предстоит заставить это работать. Во всяком случае, здесь есть «ответ», хотя он не работает для меньших массивов, которые я привел в качестве примеров в вопросе, он успешно делает то, что мне нужно было сделать. Если у кого-то есть улучшения, которые он хотел бы добавить, просто дайте мне знать.

var gaussianRefactor = function(srcOneDimentionalArray, srcMaxArrayLength) {
  var finalArray = [];
  if (srcOneDimentionalArray.length <= srcMaxArrayLength) {
    finalArray.push(srcOneDimentionalArray);
    return finalArray;
  }
  if (srcMaxArrayLength === 1) {
  for(var lengthOne = 0; lengthOne < srcOneDimentionalArray.length; lengthOne++)
    finalArray.push([srcOneDimentionalArray[lengthOne]]);
    return finalArray;
  }
  var maxArrayLength = srcMaxArrayLength;
  var oneDimentionalArray = srcOneDimentionalArray.slice(0);
  for (var x = srcMaxArrayLength; x > 1 && maxArrayLength / oneDimentionalArray.length > 0.3333; x--) {
    maxArrayLength--;
  }
  var standardChunkSize = srcOneDimentionalArray.length / maxArrayLength;
  var predictedSize = (3 * Math.floor(standardChunkSize)) % 2 === 0 ? 3 * Math.floor(standardChunkSize) + 1 : 3 * Math.floor(standardChunkSize);
  var predictedSizeCenter = Math.ceil(predictedSize / 2);
  var sigma = 0.2034185 * Math.pow(standardChunkSize, 1.963449);
  var multiplicand = 1 / (Math.sqrt(sigma) * Math.sqrt(2 * Math.PI));
  var centerGauss = maxArrayLength / multiplicand;
  var mu = 0;
  var delta;
  var fraction;
  var exponent;
  var full;
  var subArrayLength;
  var subArray;
  var notWideEnough = true;
  var maxElements;
  var maxAttempts = Math.max(Math.ceil(sigma), 100);
  var currentAttempts = 0;
  while (notWideEnough && currentAttempts < maxAttempts) {
    maxElements = 0;
    for (var j = 0; j < predictedSize; j++) {
      delta = (j - predictedSizeCenter) - mu;
      fraction = delta / Math.sqrt(sigma);
      exponent = -0.5 * Math.pow(fraction, 2);
      full = multiplicand * Math.exp(exponent);
      subArrayLength = Math.floor(full * centerGauss);
      maxElements += subArrayLength;
    }
    if (maxElements >= srcOneDimentionalArray.length) {
      notWideEnough = false;
    } else {
      sigma = sigma + sigma * 0.05;
    }
    currentAttempts++;
  }
  if (currentAttempts === maxAttempts) {
    return false;
  }

  for (var i = 0; i < predictedSize; i++) {
    delta = (i - predictedSizeCenter) - mu;
    fraction = delta / Math.sqrt(sigma);
    exponent = -0.5 * Math.pow(fraction, 2);
    full = multiplicand * Math.exp(exponent);
    subArrayLength = Math.floor(full * centerGauss);
    if (subArrayLength < 1 || oneDimentionalArray.length < 1) {
      continue;
    }
    subArray = oneDimentionalArray.slice(0, subArrayLength);
    oneDimentionalArray = oneDimentionalArray.slice(subArrayLength, oneDimentionalArray.length);
    finalArray.push(subArray);
  }
  return finalArray;
}

ВХОД

gaussianRefactor(["A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K"], 1)
gaussianRefactor(["A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K"], 2)
gaussianRefactor(["A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K"], 4)
gaussianRefactor(["A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K"], 8)
gaussianRefactor(["A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K"], 16)

OUTPUT

[["A"],["B"],["C"],["D"],["E"],["F"],["G"],["H"],["I"],["J"],["K"]]
[["A"],["B"],["C"],["D"],["E"],["F","G"],["H"],["I"],["J"],["K"]]
[["A"],["B"],["C","D"],["E","F","G"],["H","I"],["J"],["K"]]
[["A"],["B"],["C","D"],["E","F","G"],["H","I"],["J"],["K"]]
[["A","B","C","D","E","F","G","H","I","J","K"]]
...