Divida uma lista em partes de tamanho, mas sem contar itens com falha no predicado

17

Motivação : Às vezes, certos itens de uma lista não contam para o seu total. Por exemplo, contando passageiros de avião em filas, onde os bebês sentam no colo dos pais.

Desafio : escreva um programa para dividir uma lista de itens em pedaços. Cada pedaço (exceto possivelmente o último) tem o mesmo tamanho , em que tamanho é definido como o número de itens que passam por uma função predicada.

Regras :

  1. Seu programa deve levar
    • uma lista de itens
    • um tamanho de pedaço inteiro positivo
    • uma função predicada (pega um item e retorna verdadeiro ou falso)
  2. Você deve retornar a lista de entrada dividida em partes
  3. Cada pedaço é uma lista de itens
  4. No geral, os itens devem permanecer na mesma ordem, sem nenhum descartado
  5. O número de itens que passam o predicado em cada bloco (exceto possivelmente o último) deve corresponder ao tamanho do bloco de entrada.
  6. itens com falha no predicado não devem contar para esse tamanho
  7. Itens com falha no predicado são
    1. ainda incluído nos pedaços de saída
    2. alocado para o primeiro pedaço, no caso de um pedaço estar "cheio", mas os próximos itens falharem no predicado
      • portanto, o pedaço final pode não consistir apenas em itens que falham no predicado
  8. O pedaço final pode ter tamanho menor que o tamanho do pedaço, porque todos os itens foram contabilizados.

Exemplos não exaustivos:

O exemplo mais simples é considerar 1s e 0s, onde está a função predicada x ==> x > 0. Nesse caso, o sumde cada pedaço deve corresponder ao tamanho do pedaço.

  • itens :, []tamanho 2:, predicado: x > 0-> []ou[[]]
  • itens :, [0, 0, 0, 0, 0, 0]tamanho 2:, predicado: x > 0->[[0, 0, 0, 0, 0, 0]]
  • itens :, [0, 1, 1, 0]tamanho 2:, predicado: x > 0->[[0, 1, 1, 0]]
  • itens :, [0, 1, 1, 0, 1, 0, 0]tamanho 2:, predicado: x > 0->[[0, 1, 1, 0], [1, 0, 0]]
  • itens :, [0, 1, 0, 0, 1, 0, 1, 1, 0]tamanho 2:, predicado: x > 0->[[0, 1, 0, 0, 1, 0], [1, 1, 0]]

E vamos terminar com os passageiros do avião, onde os bebês se sentam no exemplo do colo dos pais . Apara adulto, bpara bebê, a fila do avião tem 3assentos largos, o adulto sempre é listado antes do bebê:

  • itens :, [A, b, A, b, A, A, A, b, A, b, A, A, b]tamanho 3:, predicado: x => x == A->[[A, b, A, b, A], [A, A, b, A, b], [A, A, b]]
Tom Viner
fonte
6
Parece uma boa pergunta, mas atualmente falta um critério de vitória. Eu sugiro usar código-golfe .
Laikoni 29/07
3
Podemos assumir que os itens da lista são caracteres únicos? Ou, digamos, números?
xnor 29/07
chunking parece interessante, mas talvez possa ser substituído por partições de conjunto .
Jonathan Frech 29/07
@Laikoni com etiquetas de código-golf
Tom Viner
1
@ Ourur eu adicionei "porque todos os itens foram contabilizados", ou seja, o último pedaço não tem chance de ficar "cheio", porque esse é apenas o final dos itens de entrada.
21418 Tom Tom-

Respostas:

2

Gelatina , 10 bytes

vⱮTm⁵ḊœṖŒṘ

Um programa completo que toma a função de caixa preta monádica como o primeiro argumento opcional, a lista como o segundo argumento opcional e o tamanho do bloco como o terceiro argumento opcional que imprime uma representação em Python da lista de listas resultante (para evitar o esmagamento implícito de Jelly na lista). listas contendo caracteres).

Experimente online! (observe que uma lista de caracteres é passada para um programa Jelly formatando-o como uma string citada em Python)

Quão?

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
fonte
8

Braquilog , 37 bytes

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

Experimente online!

Fiquei agradavelmente surpreso ao descobrir que isso - praticamente uma reafirmação da pergunta - termina com êxito e produz saída correta.

Supõe que o predicado está presente como predicado 2 abaixo deste código. Produz uma lista de listas ("chunks") ou falsepara uma entrada vazia.

Explicação:

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 - Restabelecer Monica
fonte
7

Apl (Dyalog Unicode) 17 16 bytes (SBCS)

Obrigado a Adám por me salvar 1 byte.

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

Experimente online! para fins de explicação, deixarei a solução de 17 bytes.

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

⍺⍺¨⍵aplicar o predicado à lista que retorna um vetor booleano
+\gera um total em execução que
1⌈substitui 0s com 1s
⌈⍺÷⍨divide cada elemento pelo tamanho do pedaço e arredonda as
⍵⊆⍨partições do vetor original por este

jslip
fonte
2
Isso é impressionante! E eu gosto da exibição de saída, visual apropriado para o problema.
sundar - Restabelece Monica
Salve um byte convertendo para o programa (tradfn body):w⊆⍨⌈⎕÷⍨1⌈+\⎕¨w←⎕
Adám
5

Limpo , 96 92 bytes

Usa uma função nomeada f :: a -> Boolpermitida de acordo com o 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]]=[]

Experimente online!

Expandido (com destaque padrão para que os comentários apareçam):

$ 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
Furioso
fonte
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;}

Definitivamente, Java não é a linguagem certa para esse desafio (ou qualquer desafio do codegolf, é claro ..)

-21 bytes graças a @OOBalance

Experimente online.

Explicação:

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 da caixa preta:

Supõe que uma função nomeada boolean f(Object i)esteja presente, o que é permitido de acordo com esta meta resposta .

Eu tenho uma classe abstrata Testcontendo a função padrão f(i), bem como a lambda acima:

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 os casos de teste, substituo essa função f. Por exemplo, o último caso de teste é chamado assim:

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
fonte
1
" (or any codegolf-challenge of course..)" ehh eu não sei, você venceu minhas respostas limpas em pelo menos alguns casos. De qualquer forma, estou sempre ansioso por suas respostas.
Οurous
2
@ Οurous É mais um meme que o Java não seja adequado para o codegolf de forma alguma, o que eu acho que se aplica ao Clean também se o compararmos com linguagens de golfe reais como Jelly, 05AB1E, etc. Ainda gosto de resolver todos esses desafios do codegolf embora em Java (e você também em Clean, eu assumo). E de vez em quando, o Java é capaz de vencer o Python . ;) E eu fui uma das principais respostas em Java , até que o bash a arruinou (e R jogou ainda mais). xD
Kevin Cruijssen
1
186 bytes se você retornar uma lista de matrizes: bit.ly/2mSjCIc
OOBalance
@OOBalance Thanks! Uso inteligente de Arrays.copyOfRange!
Kevin Cruijssen 30/07/2018
O @OOBalance conseguiu jogar um pouco mais usando a entrada como List e usando .sublist. Sua funcionalidade permanece a mesma, exceto isso, mas economiza muitos bytes e remove a importação. (E agora ele também funciona para o teste-caso com caracteres em vez de números inteiros.)
Kevin Cruijssen
4

R , 58 bytes

function(v,g,n,a=(cumsum(Map(g,v))-1)%/%n)split(v,a*(a>0))

Experimente online!

  • -5 bytes graças a @Giuseppe
digEmAll
fonte
1
58 bytes
Giuseppe
3

C (gcc) , 70 66 bytes

Eu uso uma estrutura para observar o início de uma sub-lista, pois C não sabe sobre essas coisas.

Obrigado ao ceilingcat pelas sugestões.

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

Experimente online!

ErikF
fonte
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]=(![])

Experimente online!

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
fonte
3

MATL, 19 bytes

HyX$Ysi/Xk1y>+!w7XQ

Baseado na excelente resposta APL do jslip .

O MATL realmente não possui funções definidas pelo usuário, mas possui uma maneira de chamar o ambiente em que está sendo executado (MATLAB / Octave), portanto, isso é usado para a função predicada. O uso seria algo parecido com isto , mas essa funcionalidade é desativada online por razões de segurança, então aqui está uma versão que usa uma isoddfunção de predicado codificada em vez disso: Experimente no 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 - Restabelecer Monica
fonte
2

Ruby , 57 bytes

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

Experimente online!

Lambda anônima que aceita matriz de entrada a, tamanho de bloco ne predicado g. Mantém um contador cde itens que correspondem ao predicado e agrupa itens pelo número de pedaços já usados. Infelizmente, o valor inicial -1 / n não chega a 0, portanto, temos que gastar alguns bytes para corrigi-lo.

Kirill L.
fonte
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],"
")

Experimente online!

superado por digEmAll

Giuseppe
fonte
Eu não sei se as listas nomeadas como saída estão ok (e se eu perdi alguns casos extremos ...): 65 bytes
digEmAll
Hummm, eu postaria isso como uma resposta separada!
Giuseppe
1

JavaScript (Node.js) , 90 bytes

(s,p,r=[l=[]],n=s+1)=>g=a=>0 in a?g(a,(n=(n||s)-p(v=a.shift()))||r.push(l=[]),l.push(v)):r

Experimente online!

Invocar como F(2, x => x > 0)([0, 1, 1, 0])

tsh
fonte
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}]]

Ungolfed:

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                  *)
  ]

lé a lista de entrada; sé o tamanho do pedaço; pé uma função sem nome / anônima / pura / lambda que retorna verdadeiro / falso operando nos elementos da lista.

Last@Reap[...]retorna uma lista de listas de todos os elementos que estavam Sow-n dentro de .... Eles são agrupados em sublistas cujo segundo argumento e~Sow~té uma abreviação Sow[e, t].

Eu tive que inicializar contadores para -1 para lidar com um tamanho de bloco de 1, caso contrário, eu precisaria verificar Mod[i, s]( i~Mod~s) igual a 1, o que nunca poderia acontecer.

O restante do código é explicado no bloco não destruído.

LLlAMnYP
fonte