J
A possible solution is to always try to place the heavier products in the boxes that have the most availability, in iterations until you can place all the products.This can be done in any language, provided you have managed to devise the algorithm to perform it. As a demonstration, I have prepared an example in SQL Server, which does more or less what I have described.First, a table for simulate the order, with some data, for example:create table #pedido (
idPedido int not null identity (1, 1) primary key
, articulo varchar(30) not null
, peso numeric(15,5) not null
, NumeroCaja int
);
insert into #pedido (articulo, peso)
values ('jabon', 17.2)
, ('shampoo', 8.4)
, ('pasta dientes', 10.7)
, ('detergente', 11.9)
, ('café', 7.5)
, ('chocolate', 6.2)
;
set nocount on;
declare @pesoMaximoCaja numeric(15,5) = 35;
declare @numCajas int;
declare @caja table (numCaja int not null, peso numeric(15,5));
declare @seContinua bit;
declare @hayPendientes bit = 1;
select @numCajas = ceiling(sum(peso)/@pesoMaximoCaja) from #pedido;
while @hayPendientes = 1
begin
set @hayPendientes = 0;
set @seContinua = 1;
with n as (select row_number() over (order by (select null)) n from sys.all_columns)
insert into @caja select n, 0 from n where n <= @numCajas;
while (@seContinua = 1)
begin
with
Resumen as (
select NumeroCaja, sum(Peso) peso
from #pedido
where NumeroCaja is not null
group by NumeroCaja
)
update c
set peso = Resumen.peso
from @Caja c
inner join Resumen on Resumen.NumeroCaja = c.numCaja;
with
Pendiente as (
select idPedido, NumeroCaja, peso, row_number() over (order by peso desc) orden
from #pedido
where NumeroCaja is null
)
,
Espacio as (
select numCaja
, peso
, @pesoMaximoCaja - peso PesoDisponible
, row_number() over (order by @pesoMaximoCaja - peso desc) orden
from @Caja
)
update Pendiente
set NumeroCaja = Espacio.numCaja
from Espacio
inner join Pendiente on Pendiente.orden = Espacio.orden
where Espacio.PesoDisponible >= Pendiente.peso;
if (@@ROWCOUNT = 0)
begin
set @hayPendientes = 1;
set @seContinua = 0;
set @numCajas += 1;
delete from @caja;
update #pedido set NumeroCaja = null;
end;
if 0 = (select count(1) from #pedido where NumeroCaja is null)
begin
set @seContinua = 0;
end;
end;
end;
set nocount off;
With the data of the first run, and this consultation:select *, sum(peso) over (partition by NumeroCaja) PesoCaja
from #pedido
order by NumeroCaja, peso desc;
We get this result:idPedido articulo peso NumeroCaja PesoCaja
1 jabon 17.20000 1 31.80000
2 shampoo 8.40000 1 31.80000
6 chocolate 6.20000 1 31.80000
4 detergente 11.90000 2 30.10000
3 pasta dientes 10.70000 2 30.10000
5 café 7.50000 2 30.10000
(6 rows affected)
The algorithm contemplates the case that we do not manage to place the products in the amount of boxes we originally estimate, so it has two nest cycles. In case you don't get it, you're adding boxes one by one until you get them all. An easy case to prove is that all products weigh more than half of the capacity of each box, which would make it impossible to put more than one product per box, but that they are close to that weight, so that the original estimate is of few boxes and has to go increasing to accommodate them all, for example, with these data:insert into #pedido (articulo, peso)
values ('jabon', 18.2)
, ('shampoo', 18.4)
, ('pasta dientes', 19.7)
, ('detergente', 21.9)
, ('café', 27.5)
, ('chocolate', 19.2)
;
We get this result:idPedido articulo peso NumeroCaja PesoCaja
5 café 27.50000 1 27.50000
4 detergente 21.90000 2 21.90000
3 pasta dientes 19.70000 3 19.70000
6 chocolate 19.20000 4 19.20000
2 shampoo 18.40000 5 18.40000
1 jabon 18.20000 6 18.20000
(6 rows affected)
I think the result, for 60 or 70 lines of code is more than acceptableHowever, I don't think he's ready to go to production (and frankly I don't think you'll find who writes that for you for free).It comes to mind some cases in which this algorithm could fail; testing and strengthening as those are found corner casesconsider it just a demonstration that it can be done and, perhaps, an initial approach to developing your own solution, still decide to do so in c# or another language in which you feel comfortable.I think the algorithm is self-explained. For doubts, observations, clarifications, we see you in the comments of this answer.