Javascript.RU

Создать новую тему Ответ
 
Опции темы Искать в теме
  #1 (permalink)  
Старый 11.06.2018, 23:27
Аватар для рони
Профессор
Отправить личное сообщение для рони Посмотреть профиль Найти все сообщения от рони
 
Регистрация: 27.05.2010
Сообщений: 33,109

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

var input = [5,10,0,12], //массив лимита каждой ячейки
    total = 7, // сумма которую надо распределить равномерно
    output = [];// результат распределения
//total = 7 => output = [2,2,0,3]
//total = 20 => output = [5,7,0,8]
//total = 40 => output = [5,10,0,12]
function fn(input, total, output) {
    for (var i = 0; total; i = ++i % input.length) {
        output[i] = output[i] || 0;
        if (output[i] + 1 > input[i]) continue;
        output[i]++;
        total--
    }
    return output
};

console.log(fn(input, total, output))//[3, 2, 0, 2]
Ответить с цитированием
  #2 (permalink)  
Старый 12.06.2018, 00:26
Аватар для j0hnik
Профессор
Отправить личное сообщение для j0hnik Посмотреть профиль Найти все сообщения от j0hnik
 
Регистрация: 01.12.2016
Сообщений: 3,650

Ровнее только с плавающей точкой.
Ответить с цитированием
  #3 (permalink)  
Старый 12.06.2018, 00:34
Аватар для рони
Профессор
Отправить личное сообщение для рони Посмотреть профиль Найти все сообщения от рони
 
Регистрация: 27.05.2010
Сообщений: 33,109

j0hnik,
все числа целые, требуется оптимизация, желательно 1 проход по массиву или 2 - 3, а не как сейчас, пока сумма по 1 не уменьшится до конца.
Ответить с цитированием
  #4 (permalink)  
Старый 12.06.2018, 00:39
Аватар для рони
Профессор
Отправить личное сообщение для рони Посмотреть профиль Найти все сообщения от рони
 
Регистрация: 27.05.2010
Сообщений: 33,109

j0hnik,
что-то типа
output[i] = Math.floor(total/input.length)
Ответить с цитированием
  #5 (permalink)  
Старый 12.06.2018, 00:44
Аватар для EmperioAf
Профессор
Отправить личное сообщение для EmperioAf Посмотреть профиль Найти все сообщения от EmperioAf
 
Регистрация: 15.01.2015
Сообщений: 622

function fn(input, total) {
  const output = [];
  const order = input.map((_, index) => index);
  const sortedOrder = order.sort((a, b) => input[b] - input[a]);
  const mustCheckIndexes = [];
  for (let i = 0; i < sortedOrder.length; i++) {
    const sortedIndex = sortedOrder[i];
    if (i === 0) {
      mustCheckIndexes.push(sortedIndex);
    } else if (input[sortedIndex] === input[sortedOrder[i - 1]]) mustCheckIndexes.push(sortedIndex);
    else break;
  }
  for (let i = 0; total; i = ++i % input.length) {
    let breakCycle = false;
    for (const mustCheckIndex of mustCheckIndexes) {
      if (output[mustCheckIndex] === input[mustCheckIndex]) breakCycle = true;
      else breakCycle = false;
    }
    if (breakCycle) break;
    const currIndex = sortedOrder[i];
    output[currIndex] = output[currIndex] || 0;
    if (output[currIndex] + 1 > input[currIndex]) {
      continue;
    }
    output[currIndex]++;
    total--
  }
  return output
};
Ответить с цитированием
  #6 (permalink)  
Старый 12.06.2018, 00:48
Аватар для j0hnik
Профессор
Отправить личное сообщение для j0hnik Посмотреть профиль Найти все сообщения от j0hnik
 
Регистрация: 01.12.2016
Сообщений: 3,650

рони,
придумал разве что проверку добавить
if(input.reduce((c,e)=> e+c) <= total) return output = [...input];

больше ничего.
Ответить с цитированием
  #7 (permalink)  
Старый 12.06.2018, 01:43
Аватар для рони
Профессор
Отправить личное сообщение для рони Посмотреть профиль Найти все сообщения от рони
 
Регистрация: 27.05.2010
Сообщений: 33,109

EmperioAf,
спасибо, попробую разобраться
j0hnik,
Rise,
спасибо, да я в курсе когда total больше суммы -- выше был минимальный пример.
Ответить с цитированием
  #8 (permalink)  
Старый 12.06.2018, 02:28
Аватар для Белый шум
Профессор
Отправить личное сообщение для Белый шум Посмотреть профиль Найти все сообщения от Белый шум
 
Регистрация: 19.01.2012
Сообщений: 505

Сообщение от рони Посмотреть сообщение
j0hnik,
что-то типа
output[i] = Math.floor(total/input.length)
Так и делай, только floor лучше заменить на ceil.

var input = [5,10,0,12], //массив лимита каждой ячейки
    total = 7, // сумма которую надо распределить равномерно
    output = [];// результат распределения
//total = 7 => output = [2,2,0,3]
//total = 20 => output = [5,7,0,8]
//total = 40 => output = [5,10,0,12]

function allocate(input, total, output) {
  var rest = total; //остаток
  var quotient = Math.ceil(total/input.length); //частное
  var waste_count = 0; //счётчик превышений
  for( var i = 0; i < input.length; i++ ){
    output[i] = output[i] || 0;
    output[i] += quotient;
    rest -= quotient;
    if( output[i] > input[i] ) {
      var waste = output[i] - input[i];
      output[i] -= waste;
      rest += waste;
      waste_count++;
    }
    if( rest <= 0 ) {
      output[i] += rest;
      break;
    }
  }
//console.log(waste_count, rest, quotient);
  if( waste_count == input.length ) return output;
  if( rest > 0 ) return allocate(input, rest, output);
  return output;
}

console.log( allocate(input, 7, []) );
console.log( allocate(input, 20, []) );
console.log( allocate(input, 40, []) );
Ответить с цитированием
  #9 (permalink)  
Старый 12.06.2018, 02:31
Аватар для рони
Профессор
Отправить личное сообщение для рони Посмотреть профиль Найти все сообщения от рони
 
Регистрация: 27.05.2010
Сообщений: 33,109

Белый шум,
спасибо!
Ответить с цитированием
  #10 (permalink)  
Старый 12.06.2018, 02:37
Аватар для рони
Профессор
Отправить личное сообщение для рони Посмотреть профиль Найти все сообщения от рони
 
Регистрация: 27.05.2010
Сообщений: 33,109

равномерное распределение суммы
вариант на котором остановился, если есть замечания напишите, всем откликнушимся большое спасибо!!!
<script>
function allocate(input, total) {
  const output = [];
  const length = input.length;
  const order = input.map((value, index) => ({value,index}));
  const sortedOrder = order.sort((a, b) => a.value - b.value);
  for (let i = 0; i < length; i++) {
    let {value,index} = sortedOrder[i];
    let num = Math.floor(total/(length - i))
    if(num > value) num = value;
    total -= num;
    output[index] = num
  }
  return output
};

let input = [5,10,0,12];
for (let total = 0; total < 41; total++) {
    let output = allocate(input, total)
    document.write(`${total}=>${output}<br>`)
}
  </script>

Последний раз редактировалось рони, 12.06.2018 в 08:39. Причина: добавлено const length
Ответить с цитированием
Ответ



Опции темы Искать в теме
Искать в теме:

Расширенный поиск


Похожие темы
Тема Автор Раздел Ответов Последнее сообщение
Как передать в массив перемеенную как ключ массива? фдуч Общие вопросы Javascript 15 11.01.2018 21:21
Как обработать переданные функции параметры как массив? javascript_pupil Общие вопросы Javascript 5 19.08.2016 13:59
Массив не принимает значение переменной как ключ wet jQuery 5 04.08.2016 08:30
Константный массив, как приватное поле класса AndreyMG Общие вопросы Javascript 0 13.05.2016 17:31
Как можно методом ajax вернуть ассоциативный массив js? Hurray AJAX и COMET 2 09.01.2016 00:19