Split a list into sized chunks, but not counting items failing predicate
Brachylog, 37 bytes
hW&t~c.k{↰₂ˢl}ᵐ;WxĖ∧.bhᵐ↰₂ᵐ∧.t↰₂ˢl≤W∧
Try it online!
I was pleasantly surprised to find that this - pretty much a restatement of the question - successfully terminates and produces correct output.
Assumes the predicate is present as predicate 2 below this code. Outputs a list of lists ("chunks"), or false
for an empty input.
Explanation:
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)
Apl (Dyalog Unicode) 17 16 bytes (SBCS)
Thanks to Adám for saving me 1 byte.
w⊆⍨⌈⎕÷⍨1⌈+\⎕¨w←⎕
Try it online! for explaination purposes I will leave up the 17 byte solution.
{⍵⊆⍨⌈⍺÷⍨1⌈+\⍺⍺¨⍵}
⍺⍺¨⍵
aplies the predicate to the list returning a boolean vector
+\
generates a running total
1⌈
replaces leading 0
s with 1
s
⌈⍺÷⍨
divides each element by the chunk size and rounds up
⍵⊆⍨
partitions the original vector by this
Clean, 96 92 bytes
Uses a named function f :: a -> Bool
allowed according to meta consensus.
import StdEnv,StdLib
$l n|l>[]=last[[i: $t n]\\i<-inits l&t<-tails l|n>=sum[1\\e<-i|f e]]=[]
Try it online!
Expanded (with default highlighting to make comments show up):
$ 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