2010-01-06 18 views
7

Me estoy preparando para una entrevista telefónica. Me encontré con estas preguntas en internet. ¿Alguien puede decirme algunas buenas respuestas para estos?¿Cómo puedo devolver una línea aleatoria desde un archivo? Pregunta de entrevista

  1. suponga que le importa un archivo de texto y pido un escribir un programa que devolverá una línea al azar a partir del archivo (todas las líneas deben tener la misma probabilidad de ser devuelto)

  2. mismo como parte 1, excepto que esta vez el archivo de texto completo no puede caber en la memoria principal

  3. Igual que en la parte 2, excepto que ahora tiene una transmisión en lugar de un archivo.

Por favor ayuda.

Ok ... @ Todos, realmente tenía algunas ideas en mi mente antes de preguntar esto ... Viendo el ataque implacable de mis compañeros SOers, estoy publicando mis respuestas. Por favor, siéntase libre de atacarlos también ...

1: Cuente el número de '\ n' en el archivo. Genere un número aleatorio entre 1 y el número y devuelva la línea después del número 1 '\ n'.

2: Traiga el archivo a la memoria principal parte por parte y siga el procedimiento anterior.

3: No tengo mucha idea sobre esto y agradecería cualquier información.

Su maravilloso que ustedes realmente dan una inspiración para seguir adelante .....

+4

@ Adam: espera, ¿qué hay de malo en hacer preguntas relacionadas con la programación en SO? –

+8

¿Está planeando dejar que Stack Overflow haga su trabajo cuando sea contratado? –

+5

¿Por qué no publicar las respuestas que tiene aquí y luego podemos sugerir cosas basadas en eso? – John

Respuesta

1

Re 1: Uso solución al 2

Re 2: Usted quiere escanear todo el archivo utilizando un RandomAccessFile acceso para contar el número de líneas y (posiblemente) almacenar en caché los punteros de archivo para cada inicio de línea. Luego puede elegir uno al azar (supongo que esta pregunta no se trata de cómo generar números aleatorios) y regresar a ese punto de inicio, leer la línea y devolverla. Si lo quiere rápido, asegúrese de que está guardando en búfer las lecturas (si no, raf es lento).

Re 3: Si la transmisión no cabe en la memoria (es decir, no se puede almacenar en caché por completo) y no sabe cuántas líneas hay en la secuencia sin leer toda la secuencia (suponiendo que solo llega a leer una vez) entonces no puedo ver una solución. Yo también espero las respuestas ...

+0

puede hacerlo sin saber el número de líneas y sin leer todas las líneas en la memoria. Ver mi respuesta para más detalles. –

22
  1. Lea todas las líneas en una matriz, devuelva una línea aleatoria en el rango de 1 y la cantidad de líneas.

  2. Más simple: Cuente las líneas, elija un número de línea al azar, revise el archivo una segunda vez y devuélvalo.

  3. Solo tiene que recordar una línea. Cada nueva línea tiene una probabilidad de 1/N (N son líneas leídas).

    Pseudocódigo:

    i = 1 
    chosen_line = "" 
    for line in lines: 
        if random() < 1/i: # random returns a uniform random number in [0,1) 
         chosen_line = line 
        i += 1 
    return chosen_line 
    

Algoritmo número 3 podría ser utilizado para 1 y 2 también.

+2

Su solución n. ° 3 es correcta, pero tal vez un poco confusa ... para aclarar, en cada línea que lea, la posibilidad de elegir la nueva línea será 1/N, donde N es el número de líneas que ha leído. Decir "elegir" (1,2,3) por ejemplo es innecesario y (IMO) confuso. Simplemente haga un seguimiento de la última línea que eligió y actualice los porcentajes sobre la marcha. +1. –

+0

@dreamlax: ese es el punto de mi último comentario ... SÓLO tiene que hacer un seguimiento de la única línea que ha elegido, y cada nueva línea que lea tendrá una posibilidad de 1/N de reemplazar esa línea. N es el número de líneas leídas "hasta ahora", no el número total de líneas en el archivo. –

+0

1: No tiene sentido leer todo el archivo en una matriz si solo quiere una línea. 2: O mejor aún (aunque menos aleatorio, probablemente): fstat() para obtener el tamaño del archivo, elija un punto al azar y lea hacia delante/atrás desde ese punto hasta que tenga una línea de texto completa. – KingRadical

-1

# 3: escriba la secuencia en un archivo en el disco y use la solución 2. No es la solución más eficiente, por supuesto, pero es muy simple.

+0

# 4: la transmisión no cabe en el disco (si lo prefiere: el dispositivo no tiene un sistema de archivos grabable). Al menos, eso es lo siguiente que diría en una entrevista, asumiendo que estaba planteando este problema desde el principio. –

+0

Sí, pero esa no era la pregunta de los OP ;-) –

9

Puede hacerlo sin tener que leer todas las líneas en la memoria, por lo que funciona bien para archivos de gran tamaño. Pseudocódigo:

linenum := 0 
ret := '' 
while more lines to read: 
    line := readline() 
    linenum := linenum + 1 
    r := uniform_random(0, linenum) 
    if r < 1: 
     ret := line 

return ret 

Prueba: Comenzamos señalando que siempre guardamos la primera línea en ret. Si el archivo tiene una línea, la va a elegir y listo.

Para el archivo de dos líneas, ret guardará la primera línea el 100% de las veces, y la segunda línea se guardará en ret el 50% del tiempo durante la segunda iteración del ciclo. Por lo tanto, cada línea tiene una probabilidad de 0.5 de ser seleccionado.

Supongamos que este método funciona para archivos de ≤ N líneas. Para demostrar que esto significa que funciona para N+1, en la iteración (N+1) del ciclo, existe una probabilidad de 1/(N+1) de que se seleccione la última línea (random(0, N+1) < 1 tiene esa probabilidad). Por lo tanto, la última línea tiene 1/(N+1) probabilidad de ser seleccionado. La probabilidad de que todas las demás líneas sean seleccionadas seguirá siendo igual entre sí, llamémoslo x. Luego, N*x + 1/(N+1) == 1, lo que significa que x = 1/(N+1).

La prueba por inducción está completa.

Editar: Vaya, no vi el tercer método de la primera respuesta antes de responder. Aún así, mantendré esta publicación aquí solo para la prueba y la oportunidad para que otras personas la corrijan si hay algún error en ella.

+0

Bueno. También podemos probarlo sin la inducción ... +1 – jslap

+0

@jslap: sí. Lo hice por inducción porque fue un ejercicio interesante para mí. :-) –

Cuestiones relacionadas