Dividir una lista en trozos de tamaño, pero sin contar los elementos que fallan predicado

17

Motivación : a veces, ciertos elementos de una lista no cuentan para sus totales. Por ejemplo, contando pasajeros de avión en filas, donde los bebés se sientan en el regazo de los padres.

Desafío : escriba un programa para dividir una lista de elementos en trozos. Cada fragmento (excepto posiblemente el último) tiene el mismo tamaño , donde el tamaño se define como el número de elementos que pasan una función de predicado.

reglas :

  1. Su programa debe tomar
    • una lista de artículos
    • un tamaño de fragmento entero positivo
    • una función de predicado (toma un elemento y devuelve verdadero o falso)
  2. Debe devolver la lista de entrada dividida en fragmentos
  3. Cada fragmento es una lista de elementos
  4. En general, los artículos deben permanecer en el mismo orden, sin descartar ninguno
  5. El número de elementos que pasan el predicado en cada fragmento (excepto posiblemente el último) debe coincidir con el tamaño del fragmento de entrada.
  6. los elementos que fallan en el predicado no deben contar para este tamaño
  7. Los elementos que fallan en el predicado son
    1. todavía incluido en los fragmentos de salida
    2. asignado al primer fragmento, en el caso de que un fragmento esté "lleno", pero los siguientes elementos son los que fallan en el predicado
      • por lo tanto, el fragmento final no puede consistir únicamente en elementos que fallan el predicado
  8. El fragmento final puede tener un tamaño menor que el tamaño del fragmento porque todos los elementos se han contabilizado.

Ejemplos no exhaustivos:

El ejemplo más simple es considerar 1sy 0s, donde está la función predicado x ==> x > 0. En este caso, el sumde cada fragmento debe coincidir con el tamaño del fragmento.

  • elementos:, []tamaño:, 2predicado: x > 0-> cualquiera []o[[]]
  • elementos:, [0, 0, 0, 0, 0, 0]tamaño:, 2predicado: x > 0->[[0, 0, 0, 0, 0, 0]]
  • elementos:, [0, 1, 1, 0]tamaño:, 2predicado: x > 0->[[0, 1, 1, 0]]
  • elementos:, [0, 1, 1, 0, 1, 0, 0]tamaño:, 2predicado: x > 0->[[0, 1, 1, 0], [1, 0, 0]]
  • elementos:, [0, 1, 0, 0, 1, 0, 1, 1, 0]tamaño:, 2predicado: x > 0->[[0, 1, 0, 0, 1, 0], [1, 1, 0]]

Y terminemos con los pasajeros del avión donde los bebés se sientan en el regazo de un padre . Apara adultos, bpara bebés, la fila del avión tiene 3asientos anchos, los adultos siempre aparecen antes que su bebé:

  • elementos:, [A, b, A, b, A, A, A, b, A, b, A, A, b]tamaño:, 3predicado: x => x == A->[[A, b, A, b, A], [A, A, b, A, b], [A, A, b]]
Tom Viner
fuente
66
Esta parece una buena pregunta, pero actualmente carece de un criterio ganador. Sugiero usar code-golf .
Laikoni
3
¿Podemos suponer que los elementos de la lista son caracteres individuales? ¿O, digamos, números?
xnor
la fragmentación suena interesante, aunque podría ser reemplazada por particiones de conjunto .
Jonathan Frech
@Laikoni etiquetó code-golf
Tom Viner
1
@Ourous He agregado "porque todos los elementos se han contabilizado", es decir, el último fragmento no tiene la oportunidad de "llenarse", porque eso es solo el final de los elementos de entrada.
Tom Viner

Respuestas:

2

Jalea , 10 bytes

vⱮTm⁵ḊœṖŒṘ

Un programa completo que toma la función de caja negra monádica como el primer argumento opcional, la lista como el segundo argumento opcional y el tamaño del fragmento como el tercer argumento opcional que imprime una representación de Python de la lista de listas resultante (para evitar la destrucción implícita de Jelly de listas que contienen caracteres).

Pruébalo en línea! (tenga en cuenta que una lista de caracteres se pasa a un programa Jelly formateándolo como una cadena citada por Python)

¿Cómo?

vⱮTm⁵ḊœṖŒṘ - Main Link: B, L, S
 Ɱ         - map across second argument with (i.e. for X in L):
v          -   evaluate as a monad with input (i.e. B(X))
  T        - truthy indices (e.g. [0,0,1,0,1,1,1,0,0,0,1,0,0]T -> [3,5,6,7,10])
    ⁵      - 3rd optional argument = S
   m       - modulo slice   (e.g. [3,4,7,9,12,15,16,18,19,20]m3 -> [[3,4,7],[9,12,15],[16,18,19],[20]]
     Ḋ     - dequeue        (e.g. [[3,4,7],[9,12,15],[16,18,19],[20]]Ḋ -> [[9,12,15],[16,18,19],[20]]
      œṖ   - partition right (L) at the indices in that
        ŒṘ - print Python representaion
Jonathan Allan
fuente
8

Brachylog , 37 bytes

hW&t~c.k{↰₂ˢl}ᵐ;WxĖ∧.bhᵐ↰₂ᵐ∧.t↰₂ˢl≤W∧

Pruébalo en línea!

Me sorprendió gratamente descubrir que esto, más o menos una reformulación de la pregunta, finaliza con éxito y produce una salida correcta.

Asume que el predicado está presente como predicado 2 debajo de este código. Emite una lista de listas ("fragmentos") o falsepara una entrada vacía.

Explicación:

hW&               % First input is W, the expected "weight" of each chunk
                  %  (i.e. the number of items passing predicate in each chunk)

t                 % Take the second input, the list of items
 ~c.              % Output is a partition of this list
    k{    }ᵐ      % For each partition (chunk) except the last, 
      ↰₂ˢ         %   Select the items in the chunk that pass the predicate
         l        %   Get the length of that
                  % (So now we have the list of the "weights" of each chunk)
            ;Wx   % Remove the input expected weight from this list, and 
               Ė  %  the result of this should be empty.
                  %  This verifies that the list of weights is either 
                  %  composed of all W-values, or is empty (when input is [0 0 0] for eg.)

    ∧.bhᵐ↰₂ᵐ      % And, the first element of each chunk (except the first) should
                  %  pass the predicate. This is another way of saying:
                  %  "Items failing the predicate are allocated to the earliest chunk"

    ∧.t↰₂ˢl≤W     % And, the final chunk (which we haven't constrained so far)
                  %  should have weight ≤ the input expected weight
                  %  This disallows putting everything in the final chunk and calling it a day!

    ∧             % (no further constraints on output)
sundar - Restablece a Monica
fuente
7

Apl (Dyalog Unicode) 17 16 bytes (SBCS)

Gracias a Adám por salvarme 1 byte.

w⊆⍨⌈⎕÷⍨1⌈+\⎕¨w←⎕

Pruébalo en línea! Para fines de explicación, dejaré la solución de 17 bytes.

{⍵⊆⍨⌈⍺÷⍨1⌈+\⍺⍺¨⍵}

⍺⍺¨⍵aplica el predicado a la lista que devuelve un vector booleano,
+\genera un total acumulado,
1⌈reemplaza 0s por 1s,
⌈⍺÷⍨divide cada elemento por el tamaño del fragmento y redondea las
⍵⊆⍨particiones del vector original por este

jslip
fuente
2
¡Eso es impresionante! Y me gusta la pantalla de salida, visual apropiada para el problema.
sundar - Restablecer Monica
Ahorre un byte convirtiéndolo en programa (cuerpo de tradfn):w⊆⍨⌈⎕÷⍨1⌈+\⎕¨w←⎕
Adám
5

Limpio , 96 92 bytes

Utiliza una función con nombre f :: a -> Boolpermitida según el meta consenso.

import StdEnv,StdLib
$l n|l>[]=last[[i: $t n]\\i<-inits l&t<-tails l|n>=sum[1\\e<-i|f e]]=[]

Pruébalo en línea!

Ampliado (con resaltado predeterminado para que aparezcan los comentarios):

$ l n // define function $ on `l` and `n`
 | l > [] // if `l` is not the empty list
  = last [ // the last element of ...
                   \\ i <- inits l // prefixes of `l`
                    & t <- tails l // matching suffixes of `l`
                    | n >= // where n is greater than or equal to
                           sum [1 \\ e <- i | f e] // the number of matching elements in the prefix
          [i: $t n] // prepend that prefix to the application of $ to the rest of the list
         ]
 = [] // if `l` is empty, return empty
Οurous
fuente
4

Java 10, 207 186 159 148 bytes

a->n->{var r=new java.util.Stack();int l=a.size(),i=0,c=0,j=0;for(;i<=l;i++)if(i==l||f(a.get(i))&&++c>n&i>0){r.add(a.subList(j,j=i));c=1;}return r;}

Java definitivamente no es el lenguaje adecuado para este desafío (o cualquier desafío de codegolf, por supuesto ...)

-21 bytes gracias a @OOBalance

Pruébalo en línea.

Explicación:

a->n->{                    // Method with List & int parameters & List of Lists return-type
  var r=new java.util.Stack();
                           //  Result-list, starting empty
  int l=a.size(),          //  Size of the input-List
      c=0,                 //  Count-integer, starting at 0
      j=0,                 //  Range-integer, starting at 0
  i=0;for(;i<=l;i++){      //  Loop `i` in the range [0, `l`]
    if(i==l||              //   If this is the last iteration
       f(a.get(i))         //   Or if the black-box function is true for the current item
       &&++c               //    Increase the counter by 1
        >n&                //    If the counter is now larger than the size
        &i>0){             //    and it's not the first item of the List
      a.subList(j,j=i);    //     Add a sub-List to the result from range [`j`, `i`)
                           //     And set `j` to `i` at the same time
      c=1;}                //     And reset `c` to 1
  return r;}               //  Return the List of Lists as result

Formato de entrada de caja negra:

Asume que hay una función con nombre boolean f(Object i), que se permite de acuerdo con esta meta respuesta .

Tengo una clase abstracta que Testcontiene la función predeterminada f(i), así como la lambda anterior:

abstract class Test{
  boolean f(Object i){
    return true;
  }

  public java.util.function.Function<java.util.List, java.util.function.Function<Integer, java.util.List<java.util.List>>> c =
    a->n->{var r=new java.util.Stack();int l=a.size(),i=0,c=0,j=0;for(;i<=l;i++)if(i==l||f(a.get(i))&&++c>n&i>0){r.add(a.subList(j,j=i));c=1;}return r;}
  ;
}

Para los casos de prueba, sobrescribo esta función f. Por ejemplo, el último caso de prueba se llama así:

System.out.println(new Test(){
  @Override
  boolean f(Object i){
    return (char)i == 'A';
  }
}.c.apply(new java.util.ArrayList(java.util.Arrays.asList('A', 'b', 'A', 'b', 'A', 'A', 'A', 'b', 'A', 'b', 'A', 'A', 'b'))).apply(3));
Kevin Cruijssen
fuente
1
" (or any codegolf-challenge of course..)" ehh no sé, has superado mis respuestas limpias en al menos algunos casos. De todos modos, siempre espero sus respuestas.
Julurous
2
@ Οurous Es más bien un meme que Java no es adecuado para codegolf de ninguna manera, lo que supongo que también se aplica a Clean si lo comparamos con lenguajes de golf reales como Jelly, 05AB1E, etc. Todavía disfruto resolviendo todos estos desafíos de codegolf en Java (y supongo que también en Clean). Y de vez en cuando (mucho), Java puede vencer a Python . ;) Y una vez fui una respuesta líder con Java , hasta que bash lo arruinó (y R jugó más). xD
Kevin Cruijssen
1
186 bytes si devuelve una Lista de matrices: bit.ly/2mSjCIc
OOBalance
@OOBalance ¡Gracias! Uso inteligente de Arrays.copyOfRange!
Kevin Cruijssen
@OOBalance ha podido jugar un poco más al golf utilizando la entrada como Lista y utilizando .sublist. Su funcionalidad sigue siendo la misma, aparte de eso, pero ahorra muchos bytes y elimina la importación. (Y ahora también funciona para el caso de prueba con caracteres en lugar de enteros.)
Kevin Cruijssen
3

C (gcc) , 70 66 bytes

Utilizo una estructura para anotar el inicio de una sublista, ya que C no sabe sobre tales cosas.

Gracias a ceilingcat por las sugerencias.

t;f(a,s,c)l*a;int(*c)();{for(;a->v;a++)(t+=c(a->v))>s?t=++a->s:0;}

Pruébalo en línea!

ErikF
fuente
3

Haskell, 72 bytes

p#s|let l@(h:t)!a|sum[1|e<-h:a,p e]>s=a:l![]|n<-a++[h]=t!n;_!a=[a]=(![])

Pruébalo en línea!

p#s     = (![])         -- main function that takes a predicate function 'p',
                        -- a size 's' and a input list without a name that is
                        -- directly passed as the first argument to function '!'
  let  l@(h:t)!a        -- function '!' is a local function (so that 'p' and 's'
                        -- are in scope). Takes a list 'l' of at least one element
                        -- 'h' (and 't' being the rest of the list) and an
                        -- accumulator 'a'
   |sum[1|e<-h:a,p e]>s -- if 'p' holds for more than 's' elements in 'h' and 'a'
     =a:l![]            --   put 'a' in front of a recursive call with the same list
                        --   'l' and an empty accumulator
   |n<-a++[h]           -- else bind 'n' to 'h' appended to 'a' and
     =t!n               --   call '!' again with 't' and 'n'
  _!a=[a]               -- base case for '!'. If the input list is empty, return
                        --   a singleton list with 'a' 
nimi
fuente
3

MATL, 19 bytes

HyX$Ysi/Xk1y>+!w7XQ

Basado en la excelente respuesta APL de jslip .

MATL realmente no tiene funciones definidas por el usuario como tales, pero tiene una forma de llamar al entorno en el que se está ejecutando (MATLAB / Octave), por lo que esto lo usa para la función de predicado. El uso sería algo como esto , pero esa funcionalidad está deshabilitada en línea por razones de seguridad, así que aquí hay una versión que utiliza una isoddfunción de predicado codificada en su lugar: Pruébelo en MATL Online .

H    % Push the function name to be called, assumed to be 
     %  stored in the H clipboard
y    % Take the first input, push copies of it both below and above the 
     %  function name
X$   % Call the function (say 'isupper') with the input as argument
     %  returns a boolean vector
Ys   % Cumulative sum
i/   % Take the chunk size and divide each element by it
Xk   % ceil
1y>+ % Turn the (initial) 0s to 1s
!    % Transpose. Now we have a column vector specifying which chunk 
     %  each input element should go into
w    % Bring the other copy of the input on top 
7    % Code for this function: '@(x){x.'}'
     %  i.e. place each chunk in a row vector and enclose it in a cell
XQ   % 'accumarray' - split the input into chunks based on
     %   the given column vector, apply the given function to each chunk
     %   (which here just wraps it up as a cell), and accumulate the results
     %   in an array.
     % implicit output
sundar - Restablece a Monica
fuente
2

Ruby , 57 bytes

->a,n,g{c=-1;a.group_by{|x|[0,c+=g[x]?1:0].max/n}.values}

Pruébalo en línea!

Matriz de entrada que acepta lambda anónima a, tamaño de fragmento ny predicado g. Mantiene un contador cde elementos que coinciden con el predicado y agrupa los elementos por el número de fragmentos ya usados. Desafortunadamente, el valor inicial -1 / n no se redondea a 0, por lo que tenemos que gastar algunos bytes para solucionarlo.

Kirill L.
fuente
2

R , 100 bytes

function(L,K,P,s=sapply(L,P),y=cut(cumsum(s),seq(0,sum(s),K),,T))for(l in levels(y))cat(L[y==l],"
")

Pruébalo en línea!

superado fácilmente por digEmAll

Giuseppe
fuente
No sé si las listas con nombre como salida están bien (y si me perdí algunos casos
extremos
¡Hmm, bueno, publicaría eso como una respuesta separada!
Giuseppe
1

Mathematica, 82 bytes

f[l_,s_,p_]:=Last@Reap[i=t=-1;Do[If[p@e,If[++i~Mod~s==0&&i>0,t++]];e~Sow~t,{e,l}]]

Sin golf:

f[l_,s_,p_] :=                (* define a function that takes three    *)
                              (* arguments                             *)

  Last@Reap[                  (* collect and return results which were *)
                              (* gathered by the procedural loop below *)

    i=t=-1;                   (* initialize two counters               *)

    Do[                       (* start iterating over the list         *)

      If[p@e,                 (* if element passes predicate           *)
        If[                   (* then if preincremented i is 0 modulo  *)
          ++i~Mod~s==0&&i>0,  (* chunk size and i > 0                  *)
          t++                 (* increment t                           *)
        ]
      ];e~Sow~t,              (* finally sow the element tagged with   *)
                              (* the current value of t                *)

    {e,l}]                    (* e references current element of list  *)
                              (* l is the list itself                  *)
  ]

les la lista de entrada; ses del tamaño de un trozo; pes una función sin nombre / anónima / pura / lambda que devuelve verdadero / falso operando en elementos de la lista.

Last@Reap[...]devuelve una lista de listas de cada elemento que estaba Sow-n dentro de .... Se agrupan en sublistas por el segundo argumento, e~Sow~tque es la abreviatura de Sow[e, t].

Tuve que inicializar los contadores a -1 para manejar un tamaño de fragmento de 1, de lo contrario tendría que marcar Mod[i, s]( i~Mod~s) igual a 1, lo que nunca podría suceder.

El resto del código se explica en el bloque sin golf.

LLlAMnYP
fuente