¿Cuál es el código más elegante que puede escribir en su lenguaje de programación favorito que imprima los números del 100 al 200?

¡Es hora de anunciar Haskell!

Este problema no es el mejor para presumir la elegancia de Haskell (o para decir que todavía soy bastante nuevo en Haskell), pero sigue siendo una frase:

let masb = if b `rem` a == 0 then Just s else Nada en [maybe (show x) id $ m 3″ abc “x m 5” def “x | x <- [100..200]]

(En realidad, también necesitará importar Data.Monoid )

Eso produce

OK, separemos el código:

[quizás (muestre x) id $ m 3 “abc” x m 5 “def” x | x <- [100..200]]
dónde
masb = if b `rem` a == 0 entonces s s else nada

Son equivalentes, pero usando “donde” puede ver que definí una función m.

Pienso en la lógica como dos pasos:

  1. Si ‘x’ es múltiplo de 3, entonces devuelva “abc” else “” (cadena vacía), si es múltiplo de 5, entonces “def” else “”, y concatenelos juntos.
  2. Si la cadena de un número sale vacía, entonces dote la forma de cadena del número en sí, es decir, muestra x .

Para el paso 1, bien podría haber usado

m ‘asb = si b `rem` a == 0 entonces s else” ”

pero luego, para el paso 2, tengo que decidir si el resultado del paso 1 está vacío, lo que me obliga a definir otra función (¡y menos elegante!)

Por lo tanto, utilicé el tipo incorporado Quizás :

datos Tal vez a = Solo a | Nada

Por ejemplo, Quizás String contiene un String dentro del constructor Just , o no contiene un String (y obtenemos Nothing ).

La cuestión es,

instancia (Monoide a) => Monoide (Quizás a)

Si un tipo es un monoide, entonces tiene un valor cero ( mempty ) y una operación para “agregar” dos valores juntos ( mappend ), por ejemplo los números: (0, +).

Para cadenas, aparentemente la estructura es (“”, ++).

Esto dice que si un es un monoide, luego envolver un interior tal vez automáticamente hace un monoide . ¿Cómo?

mempty = nada

mappend (Just x) (Just y) = Just (x `mappend` y)
mappend (Just x) (Nothing) = Just x
mappend (Nada) (Solo y) = Solo y
mappend (Nada) (Nada) = Nada

… y casi me olvido de mencionar que

= mappend

Ok, entonces el paso 1 ha finalizado, y en caso de “”, se devuelve Nothing .

La función quizás está incorporada para tratar con Quizás :

quizás :: a -> (b -> a) -> Quizás b
tal vez éxito fallido F (Solo x) = éxito F x
tal vez éxito fallido F (Nada) = fallido

Por lo tanto, podemos expresar naturalmente el paso 2: si Nothing , la cadena predeterminada es show x; de lo contrario, use la cadena dentro de Just .

En el caso de que successF sea id (la función de identidad), hay una función que guarda este id :

fromMaybe :: a -> Quizás a -> a
fromMaybe defVal (Just x) = x
fromMaybe defVal (Nothing) = defVal

pero luego tienes que importar datos .

Es natural dudar por qué usé tantos “trucos” aquí, pero en realidad son herramientas poderosas en la caja de herramientas de cualquier programador Haskell.

Y ni siquiera estoy hablando de Monad (“solo un monoide en la categoría de endofunctores, ¿cuál es el problema?”)!

Esta es la única cosa que hace que Haskell se parezca al lenguaje del doctorado en matemáticas; OK, Haskell está diseñado sobre la teoría matemática difícil, y un poco de sentido matemático ayuda a aprenderlo, pero realmente no necesitas obtener la teoría de categorías para usar Haskell (tengo un libro de texto de teoría de categorías, en caso de que no pueda dormir) , así como no necesita comprender la estructura de un automóvil para conducirlo.

Realmente no aprecio la respuesta de Scala dada, pero aquí está en Java 8:

import java.util.stream.IntStream;
import java.util.stream.Collectors;

clase pública ElegantFizzBuzz
{
public static void main (String [] args) {
System.out.println (
IntStream.rangeClosed (100, 200)
.mapToObj (x ->
(x% 3 == 0? “abc”: “”) +
(x% 5 == 0? “def”:
(x% 3> 0? “” + x: “”)))
.recoger(
Collectors.joining (“,”, “[“, “]”)));
}
}

Tenga en cuenta que podría haber utilizado Arrays.toString() lugar de collect , si hubiera utilizado toArray() en la secuencia, pero eso implicaba mezclar 2 contenedores donde solo se necesita 1, de ahí el enfoque de los Collectors .

No hace falta decir que este código se siente demasiado diseñado para su propósito, y su elegancia tiene el costo de cierta mantenibilidad.

Ah, y por si acaso, Java 8 no es mi lenguaje favorito. Scala es.

Aquí hay una versión Scala de lo mismo:

print ((100 a 200) .map (x => (if (x% 3 == 0) “abc” else “”) +
(if (x% 5 == 0) “def” else
(if (x% 3> 0) s “$ x” else “”))))

Eso es. Sin importaciones, sin nada.

O un enfoque similar a F # que utiliza la coincidencia de patrones y la pereza de un Range :

para (i <- 100 a 200) {
println (coincido con {
caso _ si i% 15 == 0 => “abcdef”
caso _ si i% 5 == 0 => “def”
caso _ si i% 3 == 0 => “abc”
caso _ => i
})
}

O incluso (Dios no lo quiera):

import java.util.stream. {IntStream, Collectors}
objeto ElegantFizzBuzz {
def main (args: Array [String]): Unit = {
System.out.println (
IntStream.rangeClosed (100, 200)
.mapToObj (x =>
(if (x% 3 == 0) “abc” else “”) +
(if (x% 5 == 0) “def” else
(if (x% 3> 0) “” + x else “”)))
.recoger(
Collectors.joining (“,”, “[“, “]”)))
}
}

(Necesita Scala 2.12+ para compatibilidad con Java 8). Sí, el enfoque de Java es directamente portátil a Scala. JVM interoperabilidad FTW!

no estoy seguro acerca de “elegante”, pero en el procedimiento no almacenado SQL como una sola “declaración” …

La parte repugnante es generar una tabla con una lista de números. No estoy seguro si soy lo suficientemente malvado como para tratar de usarlo como una pregunta de entrevista 🙂

seleccione x,
if (x mod 3 = 0 yx mod 5 = 0,
‘a B C D e F’,
if (x mod 3 = 0, ‘abc’,
if (x mod 5 = 0, ‘def’, x)
)
) como fizbiz
desde (seleccione a + 100 como x desde
(seleccione 1 como unión seleccione 2 unión seleccione 3 unión seleccione 4 unión
seleccione 5 unión seleccione 6 unión seleccione 7 unión seleccione 8 unión
seleccione 9 unión seleccione 10 unión seleccione 11 unión seleccione 12 unión
seleccione 13 unión seleccione 14 unión seleccione 15 unión seleccione 16 unión
seleccione 17 unión seleccione 18 unión seleccione 19 unión seleccione 20 unión
seleccione 21 unión seleccione 22 unión seleccione 23 unión seleccione 24 unión
seleccione 25 unión seleccione 26 unión seleccione 27 unión seleccione 28 unión
seleccione 29 unión seleccione 30 unión seleccione 31 unión seleccione 32 unión
seleccione 33 unión seleccione 34 unión seleccione 35 unión seleccione 36 unión
seleccione 37 unión seleccione 38 unión seleccione 39 unión seleccione 40 unión
seleccione 41 unión seleccione 42 unión seleccione 43 unión seleccione 44 unión
seleccione 45 unión seleccione 46 unión seleccione 47 unión seleccione 48 unión
seleccione 49 unión seleccione 50 unión seleccione 51 unión seleccione 52 unión
seleccione 53 unión seleccione 54 unión seleccione 55 unión seleccione 56 unión
seleccione 57 unión seleccione 58 unión seleccione 59 unión seleccione 60 unión
seleccione 61 unión seleccione 62 unión seleccione 63 unión seleccione 64 unión
seleccione 65 union seleccione 66 union seleccione 67 union seleccione 68 union
seleccione 69 unión seleccione 70 unión seleccione 71 unión seleccione 72 unión
seleccione 73 unión seleccione 74 unión seleccione 75 unión seleccione 76 unión
seleccione 77 unión seleccione 78 unión seleccione 79 unión seleccione 80 unión
seleccione 81 unión seleccione 82 unión seleccione 83 unión seleccione 84 unión
seleccione 85 unión seleccione 86 unión seleccione 87 unión seleccione 88 unión
seleccione 89 unión seleccione 90 unión seleccione 91 unión seleccione 92 unión
seleccione 93 union seleccione 94 union seleccione 95 union seleccione 96 union
seleccione 97 union seleccione 98 union seleccione 99 union seleccione 100
) z) y;

En C ++:

#include
#include

int main ()
{
para (size_t i = 100; i <= 200; ++ i)
{
std :: cout << (i% 3? "": "abc") << (i% 5? "": "def")
<< ((i% 3 && i% 5)? std :: to_string (i): "");
}
}

Si no te diste cuenta, me gustan los operadores ternarios.

Usando Visual FoxPro (¡aunque una línea puede remontarse a dBase II!)

1er esfuerzo

Simple, pero aburrido: solo imprime todo en una columna.

para i = 100 a 200
? iif (mod (i, 15) = 0, ‘abcdef’, iif (mod (i, 5) = 0, ‘def’, iif (mod (i, 3) = 0, ‘abc’, str (i)) ))
fin de

2do esfuerzo

Un poco más interesante: lo imprime en diagonal. Tres líneas de código, pero la segunda se envuelve cuando se importa a Quora.

para i = 100 a 200
@ i-99, i-99 dice iif (mod (i, 15) = 0, ‘abcdef’, iif (mod (i, 5) = 0, ‘def’, iif (mod (i, 3) = 0, ‘abc’, str (i))))
fin de

Creo que podría hacerlo en zigzag, pero no quiero molestarme ahora.

Trataré de expresar mi amor por la construcción del interruptor. En C, pero podría ser cualquier otro lenguaje.

#include

int main () {
para (int i = 100; i <= 200; i ++) {
interruptor (i% 15)
{
caso 0:
printf (“% s \ n”, “abcdef”);
rotura;
caso 3:
caso 6:
caso 9:
caso 12:
printf (“% s \ n”, “abc”);
rotura;
caso 5:
caso 10:
printf (“% s \ n”, “def”);
rotura;
defecto:
printf (“% d \ n”, i);
}
}
}

Erlang

Usando una lista de comprensión:

[io: formato (“~ p ~ n”, [caso {N rem 3, N rem 5} de {0,0} -> “abcdef”; {0, _} -> “abc”; {_, 0 } -> “def”; _ -> N final]) || N <- listas: seq (100.200)].

Usando el mapa:

listas: mapa (diversión (N) -> io: formato (“~ p ~ n”, [caso {N rem 3, N rem 5} de {0,0} -> “abcdef”; {0, _} – > “abc”; {_, 0} -> “def”; _ -> N end]) end, listas: seq (100,200)).

Usando el mapa (igual que el anterior) pero ligeramente expandido en múltiples expresiones para facilitar la lectura:

Imprimir = diversión (N) ->
Texto = caso {N rem 3, N rem 5} de
{0,0} -> “abcdef”;
{0, _} -> “abc”;
{_, 0} -> “def”;
_ -> N
fin,
io: formato (“~ p ~ n”, [Texto])
fin,
listas: mapa (Imprimir, listas: seq (100,200)).

Nota: Erlang REPL (erl) también imprimirá el resultado de las expresiones anteriores, que es una lista de 101 átomos de Erlang [matemáticas] ok [/ matemáticas], espero que no descalifique las respuestas 😉

Actualización : al mirar estas respuestas nuevamente, me di cuenta de que mis respuestas anteriores son cómo se haría una prueba rápida en el REPL. Práctico, y más canónico, Erlang usaría un módulo que, en algunos aspectos, daría un resultado aún más conciso debido, por ejemplo, a la sobrecarga de funciones y la coincidencia de patrones sobre los parámetros de la función.

Por ejemplo, si lo siguiente se guarda como quora.erl

-módulo (quora).
-exportar ([imprimir / 1]).

print (N) -> io: format (“~ p ~ n”, [abcdefn (N)]).
abcdefn (N) -> abcdefn (N rem 3, N rem 5, N).
abcdefn (0, 0, _) -> “abcdef”;
abcdefn (0, _, _) -> “abc”;
abcdefn (_, 0, _) -> “def”;
abcdefn (_, _, N) -> N.

Luego, en Erlang REPL, lo siguiente proporcionaría el mismo resultado que los ejemplos anteriores de Erlang anteriores:

c (quora). Comando% REPL para compilar el módulo anterior
listas: mapa (diversión quora: print / 1, listas: seq (100.200)).

Auto-proclamado el más hermoso Haskell

main = mapM putStrLn $ zipCon la opción [100 .. 200] abcdef
donde opción xy = si y == “” entonces muestra x más y
abcdef = zipWith (++) (cycle [“”, “”, “abc”]) (cycle [“def”, “”, “”, “”, “”])

Mi forma de escribir esto en Scala.

def mapPattern (x: Int): String = x match {
caso multiOf15 si x% 15 == 0 => “abcdef”
caso multiOf3 si x% 3 == 0 => “abc”
caso multiOf5 si x% 5 == 0 => “def”
caso otros => x.toString
}
(100 a 200) .foreach (x => println (mapPattern (x)))

Mi punto aquí es que el código elegante debe ser legible y extensible, esta solución tiene algunos méritos que las frases ingeniosas no tienen:

  1. Legible.
  2. Desacopla la lógica de mapeo de la iteración sobre el rango. Uno puede reutilizar fácilmente la función mapPattern en otros rangos.
  3. Eficiente. Los elementos en el rango se generan sobre la marcha (corrígeme si me equivoco).
  4. Escalable Puede agregar fácilmente nuevas condiciones especiales con un cambio de código de una línea de manera centralizada, incluso para otras personas que no están tan familiarizadas con su código.

Así es como lo haría con Haskell.

Ejemplo 1

chooseWhich :: Int -> String -> String
chooseWhich n “” = show n
elegirQu _ s = s

abcdef :: IO ()
abcdef = nulo. mapM putStrLn – Imprime cada valor, el resultado
. tomar 101 – Elija valores de 100 a 200
. soltar 100 – Ignorar valores de 0 a 99
. zipWith chooseWhich [0 ..] – Elige entre el número y la cadena
$ ciclo [“abcdef”, “”, “”, “abc”, “”,
“def”, “abc”, “”, “”, “abc”,
“def”, “”, “abc”, “”, “”]

Un comentarista solicitó alguna aclaración, así que aquí sigue una breve explicación para aquellos que no están familiarizados con Haskell.

La definición de abcdef debe leerse de principio a fin, ya que f . g f . g es equivalente a \x = f (gx) (sintaxis de Haskell), o function(x) { return f(g(x)); } function(x) { return f(g(x)); } para aquellos que conocen JavaScript. En otras palabras, g se lleva a cabo primero .

El operador $ es la aplicación de función: f . g $ x f . g $ x es simplemente f (gx) sin paréntesis.

En la primera línea, entonces (recuerde que estamos leyendo en orden inverso), estamos definiendo los primeros 3*5 elementos y repitiéndolos indefinidamente con el cycle . Las cadenas vacías son marcadores de posición para los números, lo que nos lleva a …

En la segunda línea juntamos la lista original con sus índices ( [0..] ), reemplazamos los “” : s con el índice ( cf. chooseWhich ).

En la tercera línea ignoramos los primeros 100 elementos (0 a 99) de la lista infinita.

En la cuarta línea , take los primeros 101 elementos de la lista restante, dejándonos con una lista de los valores deseados.

Por último, en la quinta línea , imprimimos cada uno de esos valores en su propia línea y descartamos la lista de valores devueltos ( sí, en Haskell, cada acción IO devuelve un valor) .

Eso es todo.

Notas

También podría generar la lista inicial de esta manera:

zipWith (++) (ciclo $ “abc”: replicar 2 [])
(ciclo $ “def”: replicar 4 [])

Puedo editar esta respuesta si pienso en algo mejor.

Ah, un clásico 🙂

Todavía no he visto ningún Forth aquí, así que desempaqué algunos viejos conocimientos arcanos y salí esto:

: ¿a B C? 3 mod 0 = dup si. “Abc” entonces;
: def? 5 mod 0 = dup si. “Def” entonces;
: ¿a B C D e F? ¿a B C? intercambiar def? o 0 =;
: elegante 201 100 do cr ii abcdef? si yo . luego bucle;

Para todos ustedes que no lo saben, después de haber escrito todo lo anterior en un Forth-Interpreter, inician el programa simplemente escribiendo “elegante”.

La elegancia como la belleza está en el ojo del espectador y, al mismo tiempo, en el pasado, Forth era mi lenguaje de programación favorito. Nada podría vencer a Forth en un AIM65.

¿Otra pregunta de FizzBuzz? De Verdad? ¿Estas seguro acerca de esto? OK, eso creo:

Importar datos. Plegable (traverse_, fold)
Importar datos. Maybe (fromMaybe)

main = traverse_ (putStrLn. transformInput) [100..200] donde
transformInput i = fromMaybe (mostrar i) $ fold [abc i, def i]
abc i | i `mod` 3 == 0 = Simplemente” abc ”
El | de lo contrario = nada
def i | i `mod` 5 == 0 = Simplemente” def ”
El | de lo contrario = nada

Aunque términos como “elegante” son altamente subjetivos. ¿Es el código más elegante el que usa la menor cantidad de caracteres? Probablemente no. ¿Es la solución más “obvia”? Tal vez, pero ¿cuál es ese? ¿O es quizás una solución particularmente inteligente (esto claramente no lo es)? Estoy realmente inseguro de lo que estás buscando exactamente.

Powershell, solo por diversión 🙂

100..200 | % {
$ salida = “”
if (-not ($ _% 3)) {$ output + = “abc”}
if (-not ($ _% 5)) {$ output + = “def”}
if ($ output -eq “”) {$ output = $ _}
escribir-host $ salida
}

En Python sin ningún escrito for bucles o declaraciones if . Solo por diversión 😀

map (lambda v: {0: “abc”, 5: “def”, True: “abcdef”}. get (no bool (v% 3 + v% 5) o v% 3 y v% 5 + 5, v ), rango (100.200))

¿Algún JS tal vez?

función abcdef (i, j) {
console.log ((i% 15 == 0 && “abcdef”) || (i% 5 == 0 && “def”) || (i% 3 == 0 && “abc”) || i);
i }
abcdef (100.200);

Una línea de Python bastante oscura usando and , or not y en lugar de la más habitual if … else … cosas.

print “\ n” .join (
no i% 15 y “ABCDEF” o no i% 3 y “ABC” o no i% 5 y “DEF” o str (i)
para i en rango (100,201))

Se basa en el hecho de que Python interpreta 0 y “” como False y cualquier otro número o cadena como True y el hecho de que:

  • and devuelve su primer argumento si se evalúa como True y su segundo argumento en todos los demás casos.
  • or devuelve su primer argumento si se evalúa como False y el segundo argumento en todos los demás casos.

Solo para agregarlo en Javascript:

para (var x = 100; x <= 200; x ++) {
var outputNumber = x;
var outputString = “”;
if (x% 3 == 0) {
outputNumber = “”;
outputString = “abc”;
}
if (x% 5 == 0) {
outputNumber = “”;
outputString + = “def”;
}
console.log (outputNumber + outputString);
}

Hay muchas respuestas a esta pregunta con código corto y legible, pero están muy lejos de las soluciones de nivel empresarial con arquitectura real, en lugar de algunas frases aleatorias. Tomemos por ejemplo mi propio enfoque ingenuo:

Consulta de C # LINQPad:

Enumerable.Range (100, 101) .ToList (). ForEach
(x => objeto nuevo [] {x, “abc”, “def”, “abcdef”} [(x% 3 == 0? 1: 0) + (x% 5 == 0? 2: 0)] .Tugurio());

Esta es la solución real de DomasM / FizzBuzzEnterpriseEdition. No es menos elegante que esos ingeniosos revestimientos o patéticos codificados para bucles con muchos ifs.

En Haskell se podría hacer lo siguiente;

divertido :: Int -> [Cadena] -> [Cadena]
divertido nr | n `rem` 15 == 0 =” abcedf “: r
El | n `rem` 5 == 0 =” def “: r
El | n `rem` 3 == 0 =” abc “: r
El | de lo contrario = (mostrar n): r

printFunny :: [Int] -> [Cadena]
printFunny = foldr gracioso []

printFunny [100..200]

En Python3.5

strs = [‘abcdef’, 0,0, ‘abc’, 0, ‘def’, ‘abc’, 0,0, ‘abc’, ‘def’, 0, ‘abc’, 0,0]
para índice en rango (100,201):
print (strs [índice% 15] si strs [índice% 15] más índice)