Trova intervalli di valori True in un elenco


26

Sfida:

Scrivi una funzione o un programma che accetta un elenco di valori booleani e restituisce tutti gli intervalli di True.

Casi test:

f [F]                               = []
f [T]                               = [[0,0]]
f [T,T,F,T]                         = [[0,1],[3,3]]
f [F,T,T,F,F,T,T,T]                 = [[1,2],[5,7]]
f [F,T,T,F,F,F,T,T,T,T]             = [[1,2],[6,9]]
f [T,T,F,F,F,T,T,T,T,T,T,T,T,T,T,F] = [[0,1],[5,14]]
f [F,F,T,T,F,F,F,F,F,F,F,F,T,T,T,T,T,T,T,T,F,F,F,F,F,F,F,F,F,F,F,F,F,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,F,F,F,F,F,F,F,F,F,F,F,F,F,F,F,F,F,F,F,F,F,F,F,F,F,F,F,F,F,F,F,F,F,F,F,F,F,F,T,T] = [[2,3],[12,19],[33,54],[93,94]]

Regole:

  • È possibile scegliere la modalità di codifica dell'input, ad esempio un elenco, un array, una stringa, ecc.
  • L'output deve essere codificato come un elenco simile a elenchi di like o una stringa che mostra tale, quindi matrici, elenchi, tuple, matrici, vettori, ecc.
  • I valori booleani devono essere codificati come costanti, ma in caso contrario è consentita qualsiasi conversione semplice di T / F in costanti desiderate
  • EDIT: è ammesso l' eval o simili durante il runtime.
  • Non dimenticare di spiegare come l'input viene passato al programma / funzione e di fornire il suo input / output per i casi di test
  • Conversione nel formato di input desiderato non conteggiato
  • Le scappatoie standard non sono ammesse
  • Se la tua lingua ha una funzione per farlo, non è permesso
  • Non accetterò la mia richiesta
  • EDIT: il formato di output è flessibile. Se non si stampa un elenco o simili, i valori di intervallo devono essere separati da un carattere non numerico e anche intervalli separati.

punteggio:

  • Il punteggio è in byte, a meno che non sia adatto alla tua lingua (come i codici in Piet)
  • Il punteggio più basso vince

C'è una buona flessibilità in input e output, ma le soluzioni in cui il T / F sono sostituite con funzioni che fanno tutto il lavoro sono vietate.

Debug:

Se scrivi il tuo in Haskell o puoi chiamarlo da Haskell, quanto segue controllerà la tua funzione / programma:

import Test.QuickCheck

tf = cycle [True,False]
gen l = foldl (++) [] $ map (\i -> [tf!!i | x<-[1..i]]) l
putIn (a,b) l = zipWith (||) l [(a <= p) && (p <= b) | p <- [0..length l]]
putAllIn rs len = foldr putIn [False|i<-[1..len]] rs
main = print $ quickCheck (check functionNameGoesHere)

1
Forse mi manca qualcosa, ma non vedo una descrizione di come viene rappresentato un intervallo nell'output.
Peter Taylor,

1
L'output può essere 1 indicizzato?
LegionMammal978,

Le gamme possono essere semi esclusive?
lirtosiast,

1
@ LegionMammal978 Solo se la lingua predefinita è 1-indicizzata, ad esempio Mathematica
Michael Klein,

@ThomasKwa No, sembra troppo diverso per i casi "limite"
Michael Klein,

Risposte:


7

Pyth, 17 16 byte

fT.b*Y,~+ZNtZrQ8

Utilizza un po 'di contro magia post-assegnazione insieme alla codifica della lunghezza della corsa.

Prende input come una matrice di 0s e 1s, ad es [1, 1, 0, 1, 0]. Risultati come nella sfida, ad es [[0, 1], [3, 3]].

Test Suite


Ho aggiunto una suite di test. Se la modifica è approvata e nessuno esegue lo snip, hai la risposta valida più breve.
Michael Klein,

9

Pyth, 18 byte

CxR.:++~Zkz02_B_`T

Suite di test

Vero è rappresentato come 1, Falso come 0.

Gli intervalli sono rappresentati in modo inclusivo.


Puoi aggiungere una spiegazione?
lirtosiast,

Certo, qualche altra volta.
isaacg,

7

Retina , 82 34 27 byte

\b(?<=(.)*_?)
$#1
_+

S_`:

La riga vuota dovrebbe contenere un singolo spazio.

L'input è una stringa piatta di _ per true e :per false. L'output è coppie separate dallo spazio, ognuna su una linea separata.

Provalo online.

Spiegazione

Il golf pesante da 82 a 27 byte è stato possibile con una scelta intelligente della rappresentazione di vero e falso. Ho scelto un carattere parola _, (che non è una cifra) per vero e un carattere non-parola :, (che non ha bisogno di scappare) per falso. Ciò mi consente di rilevare le estremità degli intervalli come limiti di parole.

\b(?<=(.)*_?)
$#1

Abbiniamo un limite di parole. Vogliamo sostituire quel confine con l'indice corrispondente del valore di verità. In linea di principio è abbastanza facile con la recente $#funzione di Retina , che conta il numero di acquisizioni di un gruppo. Catturiamo semplicemente ogni personaggio di fronte a quella posizione in un gruppo. Contando quei personaggi otteniamo la posizione. L'unico problema è che le estremità dell'intervallo sono fuori di uno ora. In realtà vogliamo l'indice del personaggio di fronte alla partita. Ciò è anche facilmente risolvibile abbinando facoltativamente una _che non è catturata, saltando così un personaggio quando siamo alla fine di un intervallo.

_+
<space>

Ora sostituiamo tutte le serie di caratteri di sottolineatura con uno spazio. Cioè, inseriamo uno spazio tra l'inizio e la fine di ogni intervallo, eliminando i caratteri di sottolineatura.

S_`:

Ciò lascia i due punti (e dobbiamo ancora separare le coppie). Lo facciamo dividendo l'intera stringa in linee attorno a ciascun punto. Gli Sattivi si dividono in modalità e _sopprime i segmenti vuoti in modo tale che non ci siano tonnellate di linee vuote quando abbiamo una serie di punti.


5

Python 2, 69 byte

p=i=0
for x in input()+[0]:
 if x-p:b=x<p;print`i-b`+';'*b,
 p=x;i+=1

Esempio di output:

2 3; 7 16; 18 18;

Un approccio diretto, nessun built-in. Tiene traccia del valore corrente xe del valore precedente p. Quando questi sono diversi, abbiamo cambiato percorso. Al passaggio 0a 1, stampa l'indice corrente i. Al passaggio 1a0 , stampa l'indice corrente meno uno seguito da un punto e virgola.

Il ifè piuttosto puzzolente. Forse la ricorsione sarebbe migliore,


5

MATL , 17 18 20 byte

j'T+'1X32X34$2#XX

Utilizza la versione corrente (9.1.0) della lingua / compilatore.

L'input è una stringa contenente caratteri Te F. L'output è una tabella a due righe, in cui ogni colonna indica un intervallo utilizzando l'indicizzazione 1, che è l'impostazione predefinita della lingua.

Grazie a Stewie Griffin per la rimozione di 2 byte.

Esempio

>> matl
 > j'T+'1X32X34$2#XX
 >
> FTTFFFTTTT
2 7
3 10

Spiegazione

Si basa su una semplice espressione regolare:

j         % input string
'T+'      % regular expression: match one or more `T` in a row
1X3       % predefined string literal: 'start'
2X3       % predefined string literal: 'end'
4$2#XX    % regexp with 4 inputs (all the above) and 2 outputs (start and end indices)
          % implicitly display start and end indices

4

Ottava, 43 byte

@(x)reshape(find(diff([0,x,0])),2,[])-[1;2]

find(diff([0,x,0]))trova tutte le posizioni in cui l'array di input cambia tra vero e falso. Rimodellando questo in una matrice 2 per n otteniamo due cose: i cambiamenti da vero a falso e da falso a vero sono divisi in due file. Ciò consente di sottrarre 1 e 2 da ciascuna di quelle righe. Sottrarre 1 dalla prima riga è necessario perché Octave è 1 indicizzata, non zero. Sottrarre 2 dalla riga due è necessario perché find(diff())trova la posizione del primo valore falso, mentre vogliamo l'ultimo valore vero. La parte di sottrazione è possibile solo in Octave, non in MATLAB.

F=0;T=1;
x=[F,F,T,T,F,F,F,F,F,F,F,F,T,T,T,T,T,T,T,T,F,F,F,F,F,F,F,F,F,F,F,F,F,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,F,F,F,F,F,F,F,F,F,F,F,F,F,F,F,F,F,F,F,F,F,F,F,F,F,F,F,F,F,F,F,F,F,F,F,F,F,F,T,T]

reshape(find(diff([0,x,0])),2,[])-[1;2]
ans =    
    2   12   33   93
    3   19   54   94

x=[T,T,F,F,F,T,T,T,T,T,T,T,T,T,T,F]
reshape(find(diff([0,x,0])),2,[])-[1;2]
ans =    
    0    5
    1   14

1
Bel uso della trasmissione!
Luis Mendo,

4

CJam, 27 25 byte

0qe`{~~{+}{1$+:X(]pX}?}/;

Si aspetta input come TTFTFT. Provalo online .

Spiegazione

0                               Push 0, to kick off index
qe`                             Push input and run length encode
                                e.g. FFFFTTTFT -> [[4 'F] [3 'T] [1 'F] [1 'T]]
{                 }/            For each pair in the RLE...
 ~                                Unwrap the pair
  ~                               Evaluate T -> 0 (falsy), F -> 15 (truthy)
   { }{         }?                 Ternary based on T/F
    +                                If 'F: add count to index
       1$+:X(]pX                     If 'T: output inclusive range, updating index
;                               Discard the remaining index at the top of the stack

4

Japt, 34 31 25 byte

Cercare un nuovo approccio ha funzionato davvero questa volta.

V=[]Ur"T+"@Vp[YY-1+Xl]};V

Provalo online!

L'input è una stringa con Ffor falsee Tfor true. L'output è una matrice di array; la rappresentazione in forma di stringa lo fa sembrare un singolo array.

Come funziona

          // Implicit: U = input string
V=[]      // Set V to an empty array. (Why don't I have a variable pre-defined to this? :P)
Ur"T+"    // Take each group of one or more "T"s in the input,
@         // and map each matched string X and its index Y to:
Vp[       //  Push the following to an array in V:
Y         //   Y,
Y-1+Xl    //   Y - 1 + X.length.
]};       //  This pushes the inclusive start and end of the string to V.
V         // Implicit: output last expression

Nota: ora vedo che diverse persone avevano già escogitato questo algoritmo, ma l'ho scoperto in modo indipendente.

Versione non competitiva, 22 byte

;Ur"T+"@Ap[YY-1+Xl]};A

In ultima GitHub commettere , ho aggiunto una nuova funzionalità: uno dei principali ;imposta le variabili A-J,Lsu valori diversi. Aè impostato su un array vuoto, eliminando così la necessità di crearlo manualmente.


3

Haskell, 74 byte

import Data.Lists
map(\l->(fst$l!!0,fst$last l)).wordsBy(not.snd).zip[0..]

Esempio di utilizzo: map(\l->(fst$l!!0,fst$last l)).wordsBy(not.snd).zip[0..] $ [True,False,True,True,False]-> [(0,0),(2,3)].

Come funziona:

                               -- example input: [True,False,True,True,False]

zip[0..]                       -- pair each element of the input with it's index
                               -- -> [(0,True),(1,False),(2,True),(3,True),(4,False)]
wordsBy(not.snd)               -- split at "False" values into a list of lists
                               -- -> [[(0,True)],[(2,True),(3,True)]]
map                            -- for every element of this list
   (\l->(fst$l!!0,fst$last l)) -- take the first element of the first pair and the
                               -- first element of the last pair
                               -- -> [(0,0),(2,3)]

3

J, 26 byte

[:I.&.|:3(<`[/,]`>/)\0,,&0

Questo è un verbo monadico senza nome (funzione unaria) che restituisce un array 2D o numeri interi. È usato come segue.

  f =: [:I.&.|:3(<`[/,]`>/)\0,,&0
  f 1 1 0 0 0 1 1 1 1 1 1 1 1 1 1 0
0  1
5 14

Spiegazione

[:I.&.|:3(<`[/,]`>/)\0,,&0
                       ,&0  Append 0 to input
                     0,     then prepend 0.
        3(         )\       For each 3-element sublist (a b c):
               ]`>/           Compute b>c
          <`[/                Compute a<b
              ,               Concatenate them
                            Now we have a 2D array with 1's on left (right) column
                            indicating starts (ends) or 1-runs.
[:I.&.|:                    Transpose, get indices of 1's on each row, transpose back.

3

Ruby, 39

->s{s.scan(/T+/){p$`.size..s=~/.#$'$/}}

Invocazione di esempio:

2.2.3 :266 > f=->s{s.scan(/T+/){p$`.size..s=~/.#$'$/}}
 => #<Proc:0x007fe8c5b4a2e8@(irb):266 (lambda)> 
2.2.3 :267 > f["TTFTTFTTTFT"]
0..1
3..4
6..8
10..10

L' ..è come Rubino rappresenta range compreso.

L'unica cosa interessante qui è come ottengo l'indice della fine dell'intervallo. È strano. Creo in modo dinamico un'espressione regolare che corrisponde all'ultimo carattere dell'intervallo, quindi a tutti i caratteri successivi e alla fine della stringa per forzare la corrispondenza corretta. Quindi uso=~ per ottenere l'indice di quel regex nella stringa originale.

Sospetto che potrebbe esserci un modo più breve per farlo in Ruby usando i flag -naF.


2

JavaScript (ES6), 59

Una funzione anonima, inserita come una stringa di TeF , che restituisce l'output come una matrice di matrici

x=>x.replace(/T+/g,(a,i)=>o.push([i,a.length+i-1]),o=[])&&o

TEST

f=x=>x.replace(/T+/g,(a,i)=>o.push([i,a.length+i-1]),o=[])&&o

// TEST

arrayOut=a=>`[${a.map(e=>e.map?arrayOut(e):e).join`,`}]`

console.log=x=>O.textContent+=x+'\n'

;[
  'F','T','TTFT','FTTFFTTT','FTTFFFTTTT','TTFFFTTTTTTTTTTF',
  'FFTTFFFFFFFFTTTTTTTTFFFFFFFFFFFFFTTTTTTTTTTTTTTTTTTTTTTFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFTT'
].forEach(t=>console.log(t+'\n'+arrayOut(f(t))+'\n'))
<pre id=O></pre>


Wow, ho appena trovato la stessa soluzione in Japt e stavo per tradurla in JS. Bello :)
ETHproductions

2

𝔼𝕊𝕄𝕚𝕟, 18 caratteri / 28 byte

ïħ`T+`,↪ᵖ[_,$Ꝉ+‡_]

Try it here (Firefox only).

Spiegazione

ïħ`T+`,↪ᵖ[_,$Ꝉ+‡_] // implicit: ï=input
ïħ`T+`,            // for each T-sequence...
       ↪ᵖ[_,$Ꝉ+‡_] // push [start index of sequence, end index of sequence] to the stack
                   // implicit stack output

2

Haskell, 62 byte

f l|s<-zip3[0..](0:l)$l++[0]=zip[i|(i,0,1)<-s][i-1|(i,1,0)<-s]

Accetta come input un elenco di 0 e 1.

Dato l'elenco l, lo riempie di 0 su entrambi i lati e calcola l'elenco indicizzato di coppie consecutive. Per esempio

l = [1,1,0]
s = [(0,0,1),(1,1,1),(2,1,0),(3,0,0)]

Quindi, estrai gli indici corrispondenti agli elementi consecutivi (0,1)e (1,0), che sono gli inizi dei blocchi di 0 e 1, sottraendo 1 dagli inizi di 0 per ottenere le estremità di 1 e comprime i risultati.


Wow, piega la sintassi più di quanto pensassi Haskell. È equivalente a "fl = let s = zip3 [0 ..] (0: l) (l ++ [0]) in zip [i | (i, 0,1) <- s] [i-1 | (i , 1,0) <- s] "?
Michael Klein,

1
@MichaelKlein Sì, ho saputo del trucco di legare le guardie da Nimi qui . È anche equivalente al più lungo binding-via-lambda f l=(\s->zip[i|(i,0,1)<-s][i-1|(i,1,0)<-s])$zip3[0..](0:l)$l++[0].
xnor

2

Pyth, 19 18 byte

m-VdU2cx1aV+ZQ+QZ2

Spiegazione:

             implicit: Q=input
m            map lambda d:
  -V         Vectorized subtraction by [0,1]
     d
     U2     
c            split every 2 elements
  x            find all indexes of
    1          1s
    aV         in vectorized xor:
       +ZQ     Q with a 0 on the front
       +QZ     Q with a 0 on the end
  2

Provalo qui .


2

Perl, 47 byte

s/F*(T*)(T)F*/[$-[0],$+[1]],/g;chop$_;$_="[$_]"

Con le seguenti opzioni perlrun -lpe:

$ perl -lpe's/F*(T*)(T)F*/[$-[0],$+[1]],/g;chop$_;$_="[$_]"' <<< 'TTFFFTTTTTTTTTTF'
[[0,1],[5,14]]

Alternativa in cui l'output è separato da linea (34 byte):

$ perl -pE's/F*(T*)(T)F*/$-[0] $+[1]\n/g;chomp' <<< TTFFFTTTTTTTTTTF
0 1
5 15

1

Python 2, 108 byte

l=input();l+=[0];o=[];s=k=0
for i,j in enumerate(l):s=j*~k*i or s;~j*l[i-1]and o.append([s,i-1]);k=j
print o

Casi test:

$ python2 rangesinlists2.py
[0]
[]
$ python2 rangesinlists2.py
[-1]
[[0, 0]]
$ python2 rangesinlists2.py
[-1,-1,0,-1]
[[0, 1], [3, 3]]
$ python2 rangesinlists2.py
[0,-1,-1,0,0,-1,-1,-1]
[[1, 2], [5, 7]]
$ python2 rangesinlists2.py
[0,-1,-1,0,0,0,-1,-1,-1,-1]
[[1, 2], [6, 9]]
$ python2 rangesinlists2.py
[-1,-1,0,0,0,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,0]
[[0, 1], [5, 14]]
$ python2 rangesinlists2.py
[0,0,-1,-1,0,0,0,0,0,0,0,0,-1,-1,-1,-1,-1,-1,-1,-1,0,0,0,0,0,0,0,0,0,0,0,0,0,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,-1,-1]
[[2, 3], [12, 19], [33, 54], [93, 94]]

Sicuramente esiste una soluzione più breve di questa, ma funziona.


1

Haskell: 123 byte (Esempio, impossibile vincere)

f l=[(s,e)|let m=length l-1,let r=[0..m],s<-r,e<-r,and[l!!x|x<-[s..e]],s<=e,let(#)p=not$l!!p,s==0||(#)(s-1),e==m||(#)(e+1)]

Meno golf:

f l = [(start,end) | start <- [0..max], end <- [0..max], allTrue start end, start <= end, notBelow start, notAbove end]
  where
    max = (length l) - 1
    allTrue s e = and (subList s e)
    subList s e = [l !! i | i <- [s,e]]
    notBelow  s = (s == 0) || (not (l !! (s-1)))
    notAbove  e = (s == m) || (not (l !! (e+1)))

Anche quando non si gioca a golf: allTrue s e = and (subList s e)o forse allTrue = (and.) . sublist.
nimi,

Ok, per un motivo che non ricordo, ho pensato che fosse più "chiaro" quando ero ungolfing ... (Modificato)
Michael Klein,

1
Oh, certo, le opinioni differiscono su ciò che è "chiaro". Penso anche che all (==True) (subList s e)sia molto chiaro.
nimi,

1

CJam, 30 byte

0l~0++2ewee{1=$2,=},{~0=-}%2/`

Input come una matrice in stile CJam di se 0e1 s. Output come una matrice di coppie in stile CJam.

Esegui tutti i casi di test. (Si occupa della conversione dei formati di input.)


1

Japt, 27 byte

A=[];Ur"T+"@Ap[YXl +´Y]};A·

Deve esserci un modo per giocare a golf ...

Comunque, è la stessa della mia 𝔼𝕊𝕄𝕚𝕟 risposta.


Caspita, ho appena escogitato questa soluzione da solo ... Bello algoritmo!
ETHproductions

1

APL, 17 caratteri

{(↑,↑∘⊖)¨⍵⊂⍵×⍳⍴⍵}

In ⎕IO←0e ⎕ML←3. In inglese:

  • ⍵×⍳⍴⍵: azzera gli elementi del vettore indice purché l'argomento in cui l'argomento sia falso
  • ⍵⊂: taglia all'inizio di ogni serie di verità e getta via i falsi
  • (↑,↑∘⊖)¨: prende il primo e l'ultimo elemento di ciascun subarray

0

PowerShell, 82 byte

("$args"|sls 't+'-A).Matches|%{if($_){'{0},{1}'-f$_.Index,($_.Index+$_.Length-1)}}

Soluzione Regex, utilizzando MatchInfo le proprietà dell'oggetto .

Esempio

PS > .\BoolRange.ps1 'F'


PS > .\BoolRange.ps1 'T'
0,0

PS > .\BoolRange.ps1 'TTFFFTTTTTTTTTTF'
0,1
5,14

0

Mathematica, 45 byte

SequencePosition[#,{True..},Overlaps->False]&

Non particolarmente interessante; usa un built-in.


0

Clojure, 109 caratteri

#(first(reduce(fn[[r i]p](let[e(+(count p)i)][(if(first p)(conj r[i(dec e)])r)e]))[[]0](partition-by not %)))

La prima cosa che mi è venuta in mente, basata su reducee partition-by.

Caso di prova semplice (mappe Tda truee Fa false):

(def f #(first(reduce(fn[[r i]p](let[e(+(count p)i)][(if(first p)(conj r[i(dec e)])r)e]))[[]0](partition-by not %))))
(f (map #(= 'T %) '[F,T,T,F,F,T,T,T]))
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.