Ceilán 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 sin golf:
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]+"...";
}
Esto es 386 bytes / caracteres. Algunas características interesantes aquí:
La x[y:z]
sintaxis es azúcar sintáctica para x.measure(y, z)
, y devuelve un subrango de x
inicio y
con longitud z
; para cadenas, esta es una subcadena. (También hay una x[y..z]
sintaxis, que es un intervalo desde el índice y a la z, ambos incluidos, así como tramos medio abiertos x[...z]
y x[y...]
).
List.lastIndexWhere
toma un predicado (es decir, una función que toma un elemento de lista y devuelve un booleano, es decir, aquí un Callable<Boolean, [Character]>
), y proporciona el índice del último elemento de lista donde se cumple el predicado (o nulo, si nunca se cumple). Como las cadenas son listas, esto también funciona para las cadenas.
El resultado de esto spaceIndex
es de tipo Integer|Null
, o Integer?
para abreviar, es decir, puede ser un número entero o null
(el único valor de tipo Null
). (El nombre spaceIndex
proviene de cuando no me di cuenta de que eso -
también era especial, supongobreakIndex
que sería mejor).
Con exists spaceIndex
podemos verificar si spaceIndex
no es nulo y hacer algo diferente entonces. (Dentro de este bloque si, el compilador sabe que no es nulo ... sin eso se habría quejado si hubiera usadospaceIndex
acceder a la cadena).
En lugar de la función local spacePredicate
, también podemos usar una función anónima
(Character char) => char == ' ' || char == '-'
Esto nos lleva 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]+"...";
}
La siguiente optimización es usar nombres más cortos de variables y funciones, lo que nos reduce en 81 bytes a 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]+"...";
}
La función de predicado en realidad no necesita su tipo de argumento declarado, que puede ser inferido por el compilador. Lo mismo para el tipo de i
(donde todavía tenemos que escribir value
para marcarlo como una declaración). Ahora esa declaración es lo suficientemente corta como para caber en una línea, llevándonos 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]+"...";
}
En lugar de e == ' ' || e == '-'
, también podemos escribir e in [' ', '-']
(o e in {' ', '-'}
, este es un constructor iterable en lugar de uno de tupla). El in
operador se asigna al método Category.contains, lo que nos lleva a la idea de que podemos pasar el contains
método de esa tupla directamente (es invocable tomar cualquier objeto, por lo que también acepta caracteres), sin el (e) => ...
repetitivo (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]+"...";
}
En realidad, otra categoría que contiene los mismos dos caracteres es la cadena de dos caracteres " -"
. (Además, también contiene sus subcadenas, pero eso no duele aquí). 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]+"...";
}
Supongo que sacamos el máximo provecho de esta línea, pasemos a las otras ... las dos últimas declaraciones de retorno tienen alguna similitud que podemos explotar: simplemente difieren en i
vs. l-3
y se usan i
solo cuando no es nulo, de lo contrario l-3
. Afortunadamente, ¡esto es exactamente para lo else
que está hecho el operador!
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)] + "...";
}
(Los paréntesis parecen ser necesarios aquí, ya que else
tiene una precedencia menor que [:]
). Esto es 171 caracteres. Ahora i
se usa solo una vez, por lo que podemos alinearlo, llevándonos 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)] + "...";
}
También podemos reemplazar esta if-return-return
combinación por una combinación de los operadores then
y else
en uno return
. ( then
devuelve el segundo operando cuando el primero es verdadero, de lo contrario es nulo, lo que luego permite else
devolver su segundo operando.) 131 bytes (aunque algunos de los ahorros son los espacios en blanco que eliminaremos de todos modos):
String t(String s, Integer l) {
return s.size < l then s else s[0:(s[0:l-2].lastIndexWhere(" -".contains) else l-3)] + "...";
}
Una función que contiene solo un retorno con una expresión puede escribirse alternativamente con la notación de "flecha gorda", dando 123:
String t(String s, Integer l) =>
s.size < l then s else s[0:(s[0:l-2].lastIndexWhere(" -".contains) else l-3)] + "...";
Eliminar el espacio en blanco innecesario nos da los 111 bytes finales:
String t(String s,Integer l)=>s.size<l then s else s[0:(s[0:l-2].lastIndexWhere(" -".contains)else l-3)]+"...";
Además, aquí hay una función que imprime los ejemplos de la pregunta (usando el nombre t
que se usa después del paso dos):
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));
}
}