Ceilão 386 333 252 230 222 216 171 153 131 111
String t(String s,Integer l)=>s.size<l then s else s[0:(s[0:l-2].lastIndexWhere(" -".contains)else l-3)]+"...";
Original Não Goleado:
String truncate(String text, Integer length) {
if(text.size < length) {
return text;
}
Boolean spacePredicate(Character char) {
return char == ' ' || char == '-';
}
Integer? spaceIndex = text[0:length-2].lastIndexWhere(spacePredicate);
if(exists spaceIndex) {
return text[0:spaceIndex] + "...";
}
return text[0:length-3]+"...";
}
São 386 bytes / caracteres. Algumas características interessantes aqui:
A x[y:z]
sintaxe é açúcar sintático para x.measure(y, z)
e retorna um subintervalo de x
início y
com comprimento z
- para seqüências de caracteres, este é um substring. (Também há x[y..z]
sintaxe, que é uma extensão do índice y até z, tanto inclusivas quanto também com aberturas pela metade x[...z]
e x[y...]
.)
List.lastIndexWhere
pega um predicado (ou seja, uma função que pega um elemento da lista e retorna um booleano, ou seja, aqui Callable<Boolean, [Character]>
) e fornece o índice do último elemento da lista em que o predicado é atendido (ou nulo, se nunca for atendido). Como strings são listas, isso também funciona para strings.
O resultado disso spaceIndex
é do tipo Integer|Null
ou, Integer?
para abreviar - ou seja, pode ser um número inteiro ou null
(o único valor do tipo Null
). (O nome spaceIndex
vem de quando eu não percebi que isso -
também era especial - acho breakIndex
que seria melhor.)
Com exists spaceIndex
podemos verificar se spaceIndex
não é nulo e, então, fazer algo diferente. (Dentro deste bloco if, o compilador sabe que não é nulo ... sem isso, teria reclamado se eu usassespaceIndex
acesso à string.)
Em vez da função local spacePredicate
, também podemos usar uma função anônima
(Character char) => char == ' ' || char == '-'
Isso nos leva a 333 caracteres:
String truncate(String text, Integer length) {
if(text.size < length) {
return text;
}
Integer? spaceIndex = text[0:length-2].lastIndexWhere(
(Character char) => char == ' ' || char == '-');
if(exists spaceIndex) {
return text[0:spaceIndex] + "...";
}
return text[0:length-3]+"...";
}
A próxima otimização é usar nomes mais curtos de variáveis e funções, o que nos reduz em 81 bytes para 252:
String t(String s, Integer l) {
if(s.size < l) {
return s;
}
Integer? i = s[0:l-2].lastIndexWhere(
(Character e) => e == ' ' || e == '-');
if(exists i) {
return s[0:i] + "...";
}
return s[0:l-3]+"...";
}
A função predicado, na verdade, não precisa do seu tipo de argumento declarado, que pode ser inferido pelo compilador. O mesmo para o tipo de i
(onde ainda precisamos escrever value
para marcá-lo como uma declaração). Agora essa declaração é curta o suficiente para caber em uma linha, reduzindo-nos a 230:
String t(String s, Integer l) {
if(s.size < l) {
return s;
}
value i = s[0:l-2].lastIndexWhere((e) => e == ' ' || e == '-');
if(exists i) {
return s[0:i] + "...";
}
return s[0:l-3]+"...";
}
Em vez de e == ' ' || e == '-'
também podemos escrever e in [' ', '-']
(ou e in {' ', '-'}
, este é um construtor iterável em vez de um tuplo). O in
operador mapeia para o método Category.contains, o que nos leva à idéia de que podemos passar o contains
método dessa tupla diretamente (é possível chamar qualquer objeto, aceitando também o caractere), sem o (e) => ...
clichê (222 bytes):
String t(String s, Integer l) {
if(s.size < l) {
return s;
}
value i = s[0:l-2].lastIndexWhere([' ', '-'].contains);
if(exists i) {
return s[0:i] + "...";
}
return s[0:l-3]+"...";
}
Na verdade, outra categoria que contém os mesmos dois caracteres é a sequência de dois caracteres " -"
. (Além disso, ele também contém suas substrings, mas isso não dói aqui). 216 bytes.
String t(String s, Integer l) {
if(s.size < l) {
return s;
}
value i = s[0:l-2].lastIndexWhere(" -".contains);
if(exists i) {
return s[0:i] + "...";
}
return s[0:l-3]+"...";
}
Acho que tiramos o máximo proveito dessa linha, vamos nos voltar para as outras ... as duas últimas declarações de retorno têm alguma semelhança que podemos explorar - elas diferem em i
vs. l-3
e estão usando i
exatamente quando não é nulo, caso contrário l-3
. Felizmente, é exatamente para isso que o else
operador é feito!
String t(String s, Integer l) {
if(s.size < l) {
return s;
}
value i = s[0:l-2].lastIndexWhere(" -".contains);
return s[0:(i else l-3)] + "...";
}
(Os parênteses parecem ser necessários aqui, pois else
têm uma precedência mais baixa que [:]
.) São 171 caracteres. Agora i
é usado apenas uma vez, para que possamos incorporá-lo, levando-nos a 153 caracteres:
String t(String s, Integer l) {
if(s.size < l) {
return s;
}
return s[0:(s[0:l-2].lastIndexWhere(" -".contains) else l-3)] + "...";
}
Também podemos substituir essa if-return-return
combinação por uma combinação dos operadores then
e else
em um return
. ( then
retorna é o segundo operando quando o primeiro é verdadeiro, caso contrário, nulo, o que permite else
retornar seu segundo operando.) 131 bytes (embora algumas das economias sejam os espaços em branco que serão eliminados de qualquer maneira):
String t(String s, Integer l) {
return s.size < l then s else s[0:(s[0:l-2].lastIndexWhere(" -".contains) else l-3)] + "...";
}
Uma função que contém apenas um retorno com uma expressão pode, alternativamente, ser escrita com a notação "flecha gorda", fornecendo 123:
String t(String s, Integer l) =>
s.size < l then s else s[0:(s[0:l-2].lastIndexWhere(" -".contains) else l-3)] + "...";
A remoção do espaço em branco desnecessário nos dá os 111 bytes finais:
String t(String s,Integer l)=>s.size<l then s else s[0:(s[0:l-2].lastIndexWhere(" -".contains)else l-3)]+"...";
Além disso, aqui está uma função que imprime os exemplos da pergunta (usando o nome t
que é usado após a etapa dois):
shared void testTruncate() {
value testInputs = {
["This is some very long text.", 25],
["This-is-some-long-hyphen-separated-text.", 33],
["Programming Puzzles & Code Golf is a question and answer site for programming puzzle enthusiasts and code golfers.", 55],
["abcdefghijklmnopqrstuvwxyz", 20],
["a b c", 4],
["Very long.", 100]
};
for(input in testInputs) {
print(t(*input));
}
}