Visualizar matriz anidada

15

Se le dará una matriz anidada. Su programa tiene que visualizar la matriz.


¿Pero cómo?

Por ejemplo, supongamos que tenemos una matriz anidada, como [["1","2"],[["1","2"],"3"],"4",[[[["5"]]]],"6"].

Esta matriz anidada se puede visualizar como:

->1
->2
-->1
-->2
->3
>4
---->5
>6

Ejemplos

Input 1:
["Atom",["Proton",["Up Quark", "Up Quark", "Down Quark"], "Neutron", ["Up Quark", "Down Quark", "Down Quark"], "Electron"]]
Output 1:
>Atom
->Proton
-->Up Quark
-->Up Quark
-->Down Quark
->Neutron
-->Up Quark
-->Down Quark
-->Down Quark
->Electron

Input 2:
[["1","2"],["3","4"]]
Output 2:
->1
->2
->3
->4

Reglas

  • Puede usar una cadena (u otros tipos que funcionan como una matriz anidada) como entrada.
  • El nivel máximo de "capas" es 2 ^ 32-1.
Matthew Roh
fuente
¿Tiene que tener esta visualización exacta?
penalosa
@mnbvc Sí, a menos que me obligue a hacerlo, la gente comienza a torcer mucho la E / S. Créeme, lo intenté.
Matthew Roh
Siento que la retina ganará esto.
Magic Octopus Urn
1
¿Hay alguna restricción sobre qué caracteres pueden aparecer en las cadenas?
Martin Ender
Preguntas relacionadas adicionales 1 , 2
AdmBorkBork

Respuestas:

12

APL, 32 bytes

{1=≡⍺:⎕←⍺,⍨⍵↑1↓⍵/'->'⋄⍺∇¨⍵+1}∘0

Prueba:

      r
┌────┬─────────────────────────────────────────────────────────────────────────────────────────┐
│Atom│┌──────┬──────────────────────────────┬───────┬────────────────────────────────┬────────┐│
│    ││Proton│┌────────┬────────┬──────────┐│Neutron│┌────────┬──────────┬──────────┐│Electron││
│    ││      ││Up Quark│Up Quark│Down Quark││       ││Up Quark│Down Quark│Down Quark││        ││
│    ││      │└────────┴────────┴──────────┘│       │└────────┴──────────┴──────────┘│        ││
│    │└──────┴──────────────────────────────┴───────┴────────────────────────────────┴────────┘│
└────┴─────────────────────────────────────────────────────────────────────────────────────────┘
      {1=≡⍺:⎕←⍺,⍨⍵↑1↓⍵/'->'⋄⍺∇¨⍵+1}∘0 ⊢ r 
>Atom
->Proton
-->Up Quark
-->Up Quark
-->Down Quark
->Neutron
-->Up Quark
-->Down Quark
-->Down Quark
->Electron

Explicación:

  • {... }∘0: ejecuta la siguiente función 0vinculada a :
    • 1=≡⍺:: si la entrada tiene profundidad 1 (es decir, una matriz que no contiene otras matrices):
      • ⍵/'->': crea una cadena que contiene -sy >s,
      • 1↓: suelte el primer elemento,
      • ⍵↑: y toma los primeros elementos. Esto da como resultado una cadena que contiene ⍵-1guiones y uno >.
      • ⍺,⍨: agregarle la entrada,
      • ⎕←: y enviarlo a la pantalla
    • : de lo contrario,
      • ⍺∇¨⍵+1: agregue 1 y aplique la función a cada matriz anidada
marinus
fuente
55
Espera, ¿se necesita información en esa forma de arte ascii?
Rɪᴋᴇʀ
44
@Riker: No, se necesita una matriz anidada normal, sin embargo, así es como Dyalog APL muestra una matriz anidada, y (pensé) hace obvio lo que está sucediendo. Puede construirlo escribiendo, por ejemplo ('Atom' ('Proton' ('Up Quark' 'Up Quark' 'Down Quark') 'Neutron' ('Up Quark' 'Down Quark' 'Down Quark') 'Electron')).
marinus
99
Ah bien. Eso lo aclara. Algo decepcionado ahora sin embargo ...
Rɪᴋᴇʀ
7

Mathematica, 58 57 56 bytes

Gracias a Greg Martin por guardar 1 byte.

Gracias a ngenisis por guardar 1 byte.

MapIndexed[Print[Table["-",Tr[1^#2]-1]<>">",#]&,#,{-1}]&
Martin Ender
fuente
47
Bienvenido a PPCG! Debe saber que las respuestas que proporcionan poca o ninguna explicación se marcan automáticamente por el sistema y terminan en la Cola de revisión de baja calidad . Eso podría eliminar su respuesta. Tenga en cuenta que si tiene varias respuestas eliminadas, puede obtener una suspensión temporal. Sólo un poco de cabeza!
Stewie Griffin
20
@StewieGriffin Gracias por la cálida bienvenida, lo tendré en cuenta.
Martin Ender
66
@StewieGriffin, ¿estás dando la bienvenida a un sitemod? ¿Que esta pasando aqui? ¿Es esto una broma interna? #confundido Y buena primavera para ustedes si están en el norte.
Mindwin
44
@Mindwin: Stack Exchange tiene un filtro diseñado para detectar respuestas que probablemente no sean útiles. Es muy probable que este tipo de publicación (título + muestra de código corto, sin comentarios) cause falsos positivos en ella, porque se parece mucho a una publicación de bajo esfuerzo en una computadora (y el comentario de Stewie Griffin contiene un enlace a una captura de pantalla que indica que de hecho sucedió un falso positivo; se está burlando de la situación). Aquí hay un ejemplo de otra publicación que quedó atrapada en el filtro.
8
@Titus Me encantaría agregar uno, pero no quiero invalidar el comentario de Stewie. :(
Martin Ender
6

Java 7, 153 141 114 bytes

String r="";<T,S>S c(S s,T o){for(T x:(T[])o)if(x instanceof Object[])c("-"+s,x);else r+=s+">"+x+"\n";return(S)r;}

-39 bytes gracias a @ Barteks2x

Explicación:

String r="";                         // Result String outside the method / on class-level
<T,S> S c(S s, T o){                 // Recursive Method with generic String and Object parameters and String return-type
  for(T x : (T[])o)                  //  Loop over the input-array
    if(x instanceof Object[])        //   If the current item is an array itself:
      c("-"+s, x);                   //    Recursive method-call with this array
    else                             //   Else:
      r += s+">"+x+"\n";             //    Append return-String with stripes String-input, ">", current item, and a new-line
                                     //  End of loop (implicit / single-line body)
  return (S)r;                       //  Return the result-String
}                                    // End of method

Código de prueba:

Pruébalo aquí.

class M{
  String r="";<T,S>S c(S s,T o){for(T x:(T[])o)if(x instanceof Object[])c("-"+s,x);else r+=s+">"+x+"\n";return(S)r;}

  public static void main(String[] a){
    M m = new M();
    System.out.println(m.c("", new Object[]{new Object[]{1,2},new Object[]{new Object[]{1,2},3},4,new Object[]{new Object[]{new Object[]{new Object[]{5}}}},6}));
    m.r = "";
    System.out.println(m.c("", new Object[]{"Atom",new Object[]{"Proton",new Object[]{"Up Quark","Up Quark","Down Quark"}},new Object[]{"Neutron",new Object[]{"Up Quark","Up Quark","Down Quark"}},"Electron"}));
  }
}

Salida:

->1
->2
-->1
-->2
->3
>4
---->5
>6

>Atom
->Proton
-->Up Quark
-->Up Quark
-->Down Quark
->Neutron
-->Up Quark
-->Up Quark
-->Down Quark
>Electron
Kevin Cruijssen
fuente
1
Puede hacerlo un poco más corto (143 o incluso 142) usando el operador ternario for(int j=i;j-->0;r+="-");para hacer también lo que hace la siguiente línea, y usando un argumento genérico en lugar de Object []: String r="";<T>String c(int i,T[] o){for(T x:o)if(x instanceof Object[])c(i+1,(T[])x);else for(int j=i;j-->=0;r+=j<0?">"+x+"\n":"-");return r;} e incluso 1 carácter menos si pasa 1 en lugar de 0 como el primero El argumento está bien.
barteks2x
Encontré una forma de hacerlo aún más corto al eliminar [] del argumento genérico, guarda 2 caracteres adicionales (pero no puedo editar el comentario después de> 5 minutos)
barteks2x
@ Barteks2x ¡Gracias! -12 bytes gracias a ti. :) Por cierto, eliminar el []del parámetro para guardar 1 byte adicional da un error. Vea el error aquí en > Depurar después de ejecutar.
Kevin Cruijssen
String r="";<T>String c(int i,T a){for(T x:(T[])a)if(x instanceof Object[])c(i+1,x);else for(int j=i;j-->0;r+=j<1?">"+x+"\n":"-");return r;}esto funciona. También puede hacer un truco genérico similar con una cadena para guardar un byte adicional, pero requiere almacenar el resultado en una variable antes de imprimirlo, o un reparto explícito (llamada al método ambiguo):String r="";<T,S>S c(int i,T a){for(T x:(T[])a)if(x instanceof Object[])c(i+1,x);else for(int j=i;j-->0;r+=j<1?">"+x+"\n":"-");return(S)r;}
barteks2x
1
No estoy seguro de si esto se considera permitido, pero 114 bytes aquí, con una cadena vacía como argumento en lugar de cero (puede ser 1 carácter menos si ">" está permitido como argumento) String r="";<T,S>S c(S p,T a){for(T x:(T[])a)if(x instanceof Object[])c("-"+p,x);else r+=p+">"+x+"\n";return(S)r;}Y el requisito de conversión de cadena en el tipo de retorno al llamar se fue.
barteks2x
6

PHP, 77 74 73 bytes

4 bytes guardados gracias @manatwork.

function f($a,$p=">"){foreach($a as$e)"$e"!=$e?f($e,"-$p"):print"$p$e
";}

función recursiva, requiere PHP 7.1 o posterior para el índice de cadena negativo.
"$e"es Arraypara matrices; entonces "$e"!=$ees lo mismo que is_array($e).

  • comenzar con el prefijo >
  • anteponer un - al prefijo para cada nivel
  • prefijo de impresión + elemento + nueva línea para átomos
Titus
fuente
1
75 bytes:function f($a,$p=""){foreach($a as$e)echo$p,is_array($e)?f($e,"-"):">$e\n";}
Ismael Miguel
1
si no fuera por el formato requerido, print_r ($ array) sería aún más pequeña :)
ivanivan
1
Hice solo una prueba rápida, pero parece que is_array($e)podría ser reemplazado por $e[-1]!=="".
manatwork
1
@manatwork Eso es PHP <7.1 ... en PHP 7.1, se puede hacer con $e[-]==""... y con la condición invertida $e[-1]>"". Buen hallazgo!
Titus
1
Tal vez echo de menos algunos casos de esquina, pero por ahora parece que $e[-1]>""se puede reemplazar "$e"==$e. Al menos en el antiguo PHP 5.6 que uso.
manatwork
5

C99 (GCC), 201 187 140 112 109

f(char*a){for(long d=1,j;j=d+=*++a>90?92-*a:0;)if(*a<35){for(;j||*++a^34;)putchar(j?"->"[!--j]:*a);puts("");}}

forma expandida:

f(char*a){
    for(long d=1,j;j=d+=*++a>90?92-*a:0;)
        if(*a<35){
            for(;j||*++a^34;)putchar(j?--j?45:62:*a);
            puts("");
        }
}

Esto toma una cadena en el formato correcto y termina cuando encuentra la última coincidencia ].

No usa recursividad y usa tipos largos para lograr la segunda regla: 2 ^ 32-1 niveles . La mayoría de los lenguajes de script tienen una profundidad de recursión limitada o simplemente se bloquean en el desbordamiento de la pila.

No estoy acostumbrado al golf en C, se agradece cualquier ayuda :)

¡Gracias a bolov por sus consejos! ¡Especialmente gracias a Titus que siempre está listo para una buena ronda de golf (incluso en C)!

Otros dos bytes guardados por el hecho de que podemos terminar una vez que coincidamos con el último ] y no sea necesario que coincida con un carácter nulo.

Se puede probar en Wandbox .

Christoph
fuente
Continuemos esta discusión en el chat .
Titus
¿No podrías acortar la segunda línea for(int d=1 ...? longtiene 4 caracteres, mientras que intsolo tiene 3, y no hay ninguna razón por la que deba hacer que supere el 2^32 - 1para que su envío sea válido, ahorrándole un solo byte.
Restioson
@Restioson int está firmado y, por lo tanto, solo funciona hasta 2^31-1.
Christoph
@Christoph el desafío declarado que usted no tiene que ir más lejos que eso.
Restioson
@Restioson El desafío establece como regla The maximum level of "layers" is 2^32-1.. 2^31-1es mucho menos 2^32-1. 2^32-1no cabe un inttiempo, se ajusta a un unsignedo long(eso está en la mayoría de los sistemas / compiladores, por supuesto). Por intlo tanto , no haría una respuesta correcta (como la mayoría de las respuestas aquí no lo son).
Christoph
4

JavaScript (ES6), 58 51 bytes

f=(a,s='>')=>a.map(e=>e.map?f(e,'-'+s):s+e).join`
`

Editar: Guarde 7 bytes cuando @Arnauld señaló que podía combinar mis dos enfoques.

Neil
fuente
4

PHP, 129 123 112 109 95 93 91 bytes

for(;a&$c=$argn[++$i];)$c<A?$c<"-"?a&$s?$s=!print"$p>$s
":0:$s.=$c:$p=substr("---$p",$c^i);

La solución iterativa toma una cadena de STDIN:
Ejecutar echo '<input>' | php -nR '<code>'o probar en línea .

Descompostura

for(;a&$c=$argn[++$i];)     // loop $c through input characters
    $c<A                        // not brackets?
        ?$c<"-"                     // comma or quote?
            ?a&$s?$s=!print"$p>$s\n":0  // if $s not empty, print and clear $s
            :$s.=$c                     // digit: append to $s
        :$p=substr("---$p",$c^i)    // prefix plus or minus one "-"
;

Feliz de que los números estén entre comillas; así que solo necesito una acción a la vez.

Violín ASCII

char    ascii   binary/comment
 "       34
 ,       44
 [       91     0101 1011
 ]       93     0101 1101

 A       65     $c<A    true for comma, quote and digits
 -       45     $c<"-"  true for comma and quote

                =0011 1010 -> 50 -> "2"
i^"["   105^91  ^0101 1011
 i      105      0110 1001
i^"]"   105^93  ^0101 1101
                =0011 0100 -> 52 -> "4"

Agregar 3 guiones $py eliminar 2 para [, 4 para ]agrega uno para [y elimina uno para ].

Titus
fuente
Buen trabajo de nuevo!
Christoph
4

Python 2, 65 64 bytes

f=lambda o,d=0:o<''and'\n'.join(f(e,d+1)for e in o)or'-'*d+'>'+o

En este momento mi respuesta comienza constantemente sin guiones, por lo que ["foo", "bar"]es:

>foo
>bar
orlp
fuente
import sys, pprint; pprint.pprint(sys.argv)es de 43 bytes pero no sé si rompe las reglas del código de golf.
Carel
Esto ahorra un byte:f=lambda o,d=0:o<''and'\n'.join(f(e,d+1)for e in o)or'-'*d+'>'+o
Ben Frankel
@Carel no puedes hacer 'importar pprint como p' o tal vez (no estoy seguro de si esto funciona) 'importar pprint.pprint como p' (Dios mío, parece que no puedo encontrar el tic en el teclado de mi teléfono)
cole
@Cole Hmm ... import sys, pprint.pprint as p; p(sys.argv)sigue siendo 43 pero una buena sugerencia, no obstante; D Intentarlo en import sys.argv as vrealidad lo alarga un poco ~ 48 bytes. Si uno pudiera eliminar sys.argv, ahorraría mucho, pero el programa se vuelve bastante inútil. Un enfoque recursivo es bastante largo def p(L,d=0): [p(i,d+1) if isinstance(i,list) else print(">"*d + i) for i in L], ~ 80 bytes.
Carel
3

Perl 5 , 55 bytes

53 bytes de código + -nlbanderas.

/"/?print"-"x~-$v.">$_":/]/?$v--:$v++for/]|\[|".*?"/g

Pruébalo en línea!

No es óptimo para la expresión regular debido a algunos casos nerviosos que podrían ocurrir (en particular, si un elemento de la matriz contiene corchetes en su interior).
Sin embargo, una función anónima recursiva sería apenas más larga (61 bytes):

sub f{my$v=pop;map{ref?f(@$_,$v+1):"-"x$v.">$_"}@_}sub{f@_,0}

Pruébalo en línea!

Pero la forma en que Perl maneja los parámetros no es óptima para las funciones de golf: sin parámetros opcionales significa que tengo que hacer una segunda función (anónima) llamando a la primera, y tengo que obtener explícitamente el último parámetro con ese tiempo my$v=pop.

Dada
fuente
3

Ruby, 49 45 46 bytes

f=->c,p=?>{c.map{|x|x==[*x]?f[x,?-+p]:p+x}*$/}

Ejemplo:

puts f[["Atom",["Proton",["Up Quark", "Up Quark", "Down Quark"], "Neutron", ["Up Quark", "Down Quark", "Down Quark"], "Electron"]]]

>Atom
->Proton
-->Up Quark
-->Up Quark
-->Down Quark
->Neutron
-->Up Quark
-->Down Quark
-->Down Quark
->Electron

Explicación:

Función recursiva: si x==[*x]entonces x es una matriz, e iteramos sobre ella. Si no, sangrarlo.

GB
fuente
3

Haskell, 104 bytes

l@(x:y)#(a:m)|[(h,t)]<-reads$a:m=y++h++l#t|a<'#'=l#m|a<'-'='\n':l#m|a>'['=y#m|q<-'-':l=q#m
l#_=""
(">"#)

Haskell no tiene listas anidadas con diferentes profundidades, por lo que tengo que analizar la cadena de entrada por mi cuenta. Afortunadamente, la función de biblioteca readspuede analizar cadenas (es decir, "secuencia de caracteres incluida), por lo que tengo un poco de ayuda aquí.

Ejemplo de uso:

*Main> putStrLn $ (">"#) "[[\"1\",\"2\"],[\"3\",\"4\"]]" 
->1
->2
->3
->4

Pruébalo en línea! .

Cómo funciona:

La función #pasa por la cadena char por char y mantiene el nivel de anidamiento (el primer parámetro l) como una cadena de -con un final >. Si el encabezado de la lista se puede analizar como una Cadena, tome ly la Cadena seguida de una llamada recursiva con la Cadena eliminada. Si el primer carácter es un espacio, sáltelo. Si es a ,, tome una nueva línea y continúe, si es así ], baje el nivel de anidación y continúe y de lo contrario (solo a la [izquierda) aumente el nivel de anidación y continúe. La recursión termina con la cadena de entrada vacía. La función principal (">"#)establece el nivel de anidamiento ">"y las llamadas #.

nimi
fuente
2

SWI-Prolog, 115 bytes

p(L):-p(L,[>]).
p([],_):-!.
p([H|T],F):-p(H,[-|F]),p(T,F),!.
p(E,[_|F]):-w(F),w([E]),nl.
w([]).
w([H|T]):-write(H),w(T).

Se agregaron saltos de línea solo para facilitar la lectura, no incluidos en el recuento de bytes.

pel predicado atraviesa recursivamente las matrices, agregando un '-' al prefijo Fcuando se mueve un nivel más profundo.wse usa para escribir la matriz de prefijos, así como el elemento real en la salida.

Ejemplo:

?- p(["Atom",["Proton",["Up Quark", "Up Quark", "Down Quark"], "Neutron", ["Up Quark", "Down Quark", "Down Quark"], "Electron"]]).
>Atom
->Proton
-->Up Quark
-->Up Quark
-->Down Quark
->Neutron
-->Up Quark
-->Down Quark
-->Down Quark
->Electron
Steven
fuente
2

Lote, 249 bytes

@echo off
set/ps=
set i=
:t
set t=
:l
set c=%s:~,1%
set s=%s:~1%
if "%c%"=="[" set i=-%i%&goto l
if not "%c%"=="]" if not "%c%"=="," set t=%t%%c%&goto l
if not "%t%"=="" echo %i:~1%^>%t%
if "%c%"=="]" set i=%i:~1%
if not "%s%"=="" goto t

Molesto, Batch tiene problemas para comparar comas. Ejecución de muestra:

[Atom,[Proton,[Up Quark,Up Quark,Down Quark],Neutron,[Up Quark,Down Quark,Down Quark],Electron]]
>Atom
->Proton
-->Up Quark
-->Up Quark
-->Down Quark
->Neutron
-->Up Quark
-->Down Quark
-->Down Quark
->Electron
Neil
fuente
2

Retina , 63 54 52 bytes

Guardado 2 bytes gracias a Martin Ender

.*?".*?"
$`$&¶
T`[] -~`-]_`.(?=.*".*")
-]

-"
>
T`]"

Pruébalo en línea!

Explicación

.*?".*?"
$`$&¶

Primero, la matriz se divide reemplazando cada cadena entrecomillada con todo lo que vino antes, más ella misma, más una nueva línea. Al dividirlo de esta manera, es posible encontrar los corchetes de apertura inigualables antes de cada cadena.

T`[] -~`-]_`.(?=.*".*")

Esta transliteración reemplazará [con -, dejará ]sin cambios y eliminará cualquier otro carácter (  -~es todo ASCII imprimible). Sin embargo, solo reemplaza los caracteres que aparecen antes de la cadena final en cada línea.

-]

A continuación, -]se eliminan todas las instancias de . Estos corresponden a pares de corchetes coincidentes, y solo queremos corchetes no coincidentes. Después de que se eliminen, cada línea tiene un número de -s igual a la cantidad de paréntesis de apertura que no coinciden .

-"
>

El último -antes de a "se reemplaza por >, para formar las flechas.

T`]"

Finalmente, todos los ]sys restantes "se eliminan.

Gato de negocios
fuente
Parece que supone que no habrá comillas (escapadas) dentro de las cadenas. No estoy seguro de si eso es legítimo, pero he pedido una aclaración.
Martin Ender
@MartinEnder Buena captura, lo vigilaré
Business Cat
1

Röda , 54 bytes

f d=""{{|n|{n|f d=`$d-`}if[n is list]else[`$d>$n
`]}_}

Pruébalo en línea!

Es una función que lee la matriz de entrada de la secuencia. Para cada elemento, se llama a sí mismo de forma recursiva o imprime el elemento.

fergusq
fuente
1

Python 3, 80 bytes

Parece que las lambdas de Python respaldan la recursividad, ¿quién sabía?

p=lambda l,d=1:[p(i,d+1)if isinstance(i,list)else print("-"*d+">"+i)for i in l]

Este es un contador / cumplido a la respuesta de orlp .

Carel
fuente
Bienvenido a PPCG! Parece que has contado un salto de línea final o algo así (porque solo cuento 80 bytes) y no necesitas los espacios alrededor del =. También sospecho que puedes dejar todos los espacios después de los tres ), pero no estoy muy familiarizado con el golf en Python.
Martin Ender
0

Groovy, 92 bytes

x={a,b->if(a instanceof List){a.each{x(it,b+1)}}else{y(a,b)}};y={a,b->println("-"*b+">$a")};
Urna de pulpo mágico
fuente
0

Apilado , 27 bytes

[@.1-'-'*\'>'\,,out]deepmap

Pruébalo en línea!

Toma la entrada desde la parte superior de la pila y deja la salida en STDOUT. Esto es simple como hacer un mapa de profundidad, repetir- d tiempos, concatenar con '>' y el elemento en sí.

Conor O'Brien
fuente
0

Gema, 63 personajes

\A=@set{i;-1}
[=@incr{i}
]=@decr{i}
"*"=@repeat{$i;-}>*\n
,<s>=

Al igual que las otras soluciones de análisis, se supone que no habrá comillas dobles escapadas en las cadenas.

Ejecución de muestra:

bash-4.3$ gema '\A=@set{i;-1};[=@incr{i};]=@decr{i};"*"=@repeat{$i;-}>*\n;,<s>=' <<< '[["1","2"],[["1","2"],"3"],"4",[[[["5"]]]],"6"]'
->1
->2
-->1
-->2
->3
>4
---->5
>6
hombre trabajando
fuente
0

jq, 70 67 caracteres

( 67 código de 64 caracteres + opción de línea de comando de 3 caracteres)

def f(i):if type=="array"then.[]|f("-"+i)else i+. end;.[]|f(">")

Ejecución de muestra:

bash-4.3$ jq -r 'def f(i):if type=="array"then.[]|f("-"+i)else i+. end;.[]|f(">")' <<< '[["1","2"],[["1","2"],"3"],"4",[[[["5"]]]],"6"]'
->1
->2
-->1
-->2
->3
>4
---->5
>6

Prueba en línea

hombre trabajando
fuente