Подтвердить что ты не робот

Поиск уникальных символов в файле

У меня есть файл с 450 000 + строками записей. Каждая запись имеет длину около 7 символов. Я хочу знать уникальные символы этого файла.

Например, если мой файл был следующим:

Entry
-----
Yabba
Dabba
Doo

Тогда результатом будет

Уникальные символы: {abdoy}

Обратите внимание: мне все равно, и не нужно заказывать результаты. Что-то говорит мне, что это очень легко для Linux-пользователей решить.

Update

Я ищу очень быстрое решение. Я действительно не хочу создавать код, чтобы перебирать каждую запись, прокручивать каждый символ... и так далее. Я ищу хорошее решение script.

Обновление 2

По Быстро, я имею в виду, что быстро реализовать... не обязательно быстро запускать.

4b9b3361

Ответ 1

Вот пример PowerShell:

gc file.txt | select -Skip 2 | % { $_.ToCharArray() } | sort -CaseSensitive -Unique

который производит:

D
 Y
 
 б
 o

Мне нравится, что его легко читать.

EDIT: здесь более быстрая версия:

$letters = @{} ; gc file.txt | select -Skip 2 | % { $_.ToCharArray() } | % { $letters[$_] = $true } ; $letters.Keys

Ответ 2

BASH версия оболочки script (нет sed/awk):

while read -n 1 char; do echo "$char"; done < entry.txt | tr [A-Z] [a-z] |  sort -u

UPDATE: просто для этого, так как мне было скучно и все еще думать об этой проблеме, здесь используется версия С++ с использованием set. Если время выполнения важно, это будет мой рекомендуемый вариант, так как версия С++ занимает чуть больше половины секунды для обработки файла с 450 000+ записей.

#include <iostream>
#include <set>

int main() {
    std::set<char> seen_chars;
    std::set<char>::const_iterator iter;
    char ch;

    /* ignore whitespace and case */
    while ( std::cin.get(ch) ) {
        if (! isspace(ch) ) {
            seen_chars.insert(tolower(ch));
        }
    }

    for( iter = seen_chars.begin(); iter != seen_chars.end(); ++iter ) {
        std::cout << *iter << std::endl;
    }

    return 0;
}

Обратите внимание, что я игнорирую пробелы и не учитываю регистр в соответствии с запросом.

Для файла записи 450 000+ (chars.txt) здесь пример времени выполнения:

[[email protected]]$ g++ -o unique_chars unique_chars.cpp 
[[email protected]]$ time ./unique_chars < chars.txt
a
b
d
o
y

real    0m0.638s
user    0m0.612s
sys     0m0.017s

Ответ 3

В соответствии с запросом, чистое решение оболочки script ":

sed -e "s/./\0\n/g" inputfile | sort -u

Это нехорошо, это не быстро, а вывод не совсем точно указан, но он должен работать... в основном.

Для еще более смехотворности я представляю версию, которая выгружает вывод в одной строке:

sed -e "s/./\0\n/g" inputfile | sort -u | while read c; do echo -n "$c" ; done

Ответ 4

Используйте структуру данных set. Большинство языков программирования/стандартных библиотек имеют один вкус или другой. Если они этого не делают, используйте хеш-таблицу (или вообще, словарь) и просто опустите поле значения. Используйте символы в качестве ключей. Эти структуры данных обычно отфильтровывают повторяющиеся записи (следовательно, имя set, из его математического использования: наборы не имеют определенного порядка и только уникальные значения).

Ответ 5

Быстрая и грязная программа C, которая невероятно быстро:

#include <stdio.h>

int main(void)
{
  int chars[256] = {0}, c;
  while((c = getchar()) != EOF)
    chars[c] = 1;
  for(c = 32; c < 127; c++)  // printable chars only
  {
    if(chars[c])
      putchar(c);
  }

  putchar('\n');

  return 0;
}

Скомпилируйте его, затем сделайте

cat file | ./a.out

Чтобы получить список уникальных печатаемых символов в file.

Ответ 6

Python с наборами (быстрые и грязные)

s = open("data.txt", "r").read()
print "Unique Characters: {%s}" % ''.join(set(s))

Python с наборами (с более приятным выходом)

import re

text = open("data.txt", "r").read().lower()
unique = re.sub('\W, '', ''.join(set(text))) # Ignore non-alphanumeric

print "Unique Characters: {%s}" % unique

Ответ 7

Очень быстрым решением было бы сделать небольшую программу на C, которая читает свой стандартный ввод, выполняет агрегацию и выплевывает результат.

Почему произвольное ограничение, которое вам нужно "script", которое делает это?

Что такое script?

Будет ли Python делать?

Если это так, то это одно решение:

import sys;

s = set([]);
while True:
    line = sys.stdin.readline();
    if not line:
        break;
    line = line.rstrip();
    for c in line.lower():
        s.add(c);

print("".join(sorted(s)));

Ответ 8

Алгоритм:   Slurp файл в память.

Create an array of unsigned ints, initialized to zero.

Iterate though the in memory file, using each byte as a subscript into the array.
    increment that array element.

Discard the in memory file

Iterate the array of unsigned int
       if the count is not zero,
           display the character, and its corresponding count.

Ответ 9

cat yourfile | 
 perl -e 'while(<>){chomp;$k{$_}++ for split(//, lc $_)}print keys %k,"\n";'

Ответ 10

Альтернативное решение с использованием bash:

sed "s/./\l\0\n/g" inputfile | sort -u | grep -vc ^$

ИЗМЕНИТЬ Извините, я на самом деле неправильно понял вопрос. Вышеприведенный код подсчитывает уникальные символы. Просто опустить переключатель c в конце, очевидно, делает трюк, но затем это решение не имеет реального преимущества для saua (тем более что теперь он использует тот же шаблон sed вместо явных захватов).

Ответ 11

Пока не script, эта java-программа выполнит эту работу. Легко понять быстрый (для запуска)

import java.util.*;
import java.io.*;
public class  Unique {
    public static void main( String [] args ) throws IOException { 
        int c = 0;
        Set s = new TreeSet();
        while( ( c = System.in.read() ) > 0 ) {
            s.add( Character.toLowerCase((char)c));
        }
        System.out.println( "Unique characters:" + s );
    }
}

Вы будете вызывать это следующим образом:

type yourFile | java Unique

или

cat yourFile | java Unique

Например, уникальные символы в HTML этого вопроса:

Unique characters:[ , , ,  , !, ", #, $, %, &, ', (, ), +, ,, -, ., /, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, :, ;, <, =, >, ?, @, [, \, ], ^, _, a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, v, w, x, y, z, {, |, }]

Ответ 12

в С++ я сначала прокручу буквы в алфавите, а затем запустим strchr() для каждого с файлом в виде строки. это скажет вам, существует ли эта буква, а затем просто добавьте ее в список.

Ответ 13

Python без использования набора.

file = open('location', 'r')
letters = []
for line in file:
    for character in line:
        if character not in letters:
            letters.append(character)

Ответ 14

Попробуйте этот файл с JSDB Javascript (включает механизм javascript в браузере Firefox):

var seenAlreadyMap={};
var seenAlreadyArray=[];
while (!system.stdin.eof)
{
  var L = system.stdin.readLine();
  for (var i = L.length; i-- > 0; )
  {
    var c = L[i].toLowerCase();
    if (!(c in seenAlreadyMap))
    {
      seenAlreadyMap[c] = true;
      seenAlreadyArray.push(c);
    }
  }
}
system.stdout.writeln(seenAlreadyArray.sort().join(''));

Ответ 15

Python с использованием словаря. Я не знаю, почему люди так привязаны к наборам или спискам, чтобы держать вещи. Предоставленный набор, вероятно, более эффективен, чем словарь. Тем не менее, как предполагается, требуется постоянное время для доступа к элементам. И оба запускают круги вокруг списка, где для каждого символа вы просматриваете список, чтобы увидеть, находится ли символ в списке или нет. Также списки и словари построены в типах данных Python, которые все должны использовать все время. Поэтому даже если набор не приходит в голову, словарь должен.

file = open('location.txt', 'r')
letters = {}
for line in file:
  if line == "":
    break
  for character in line.strip():
    if character not in letters:
      letters[character] = True
file.close()
print "Unique Characters: {" + "".join(letters.keys()) + "}"

Ответ 16

A C-решение. По общему признанию, это не самое быстрое решение для кода в мире. Но поскольку он уже закодирован и может быть вырезан и вставлен, я думаю, что он считается "быстрым для реализации" для плаката:) Я фактически не видел никаких C-решений, поэтому я хотел опубликовать одно для чистого садистского удовольствия:)

#include<stdio.h>

#define CHARSINSET 256
#define FILENAME "location.txt"

char buf[CHARSINSET + 1];

char *getUniqueCharacters(int *charactersInFile) {
    int x;
    char *bufptr = buf;
    for (x = 0; x< CHARSINSET;x++) {
        if (charactersInFile[x] > 0)
            *bufptr++ = (char)x;
    }
    bufptr = '\0';
    return buf;
}

int main() {
    FILE *fp;
    char c;
    int *charactersInFile = calloc(sizeof(int), CHARSINSET);
    if (NULL == (fp = fopen(FILENAME, "rt"))) {
        printf ("File not found.\n");
        return 1;
    }
    while(1) {
        c = getc(fp);
        if (c == EOF) {
            break;
        }
        if (c != '\n' && c != '\r')
            charactersInFile[c]++;
    }

    fclose(fp);
    printf("Unique characters: {%s}\n", getUniqueCharacters(charactersInFile));
    return 0;
}

Ответ 17

Где C:/data.txt содержит 454 863 строки из семи случайных буквенных символов, следующий код

using System;
using System.IO;
using System.Collections;
using System.Diagnostics;

namespace ConsoleApplication {
    class Program {
        static void Main(string[] args) {
            FileInfo fileInfo = new FileInfo(@"C:/data.txt");
            Console.WriteLine(fileInfo.Length);

            Stopwatch sw = new Stopwatch();
            sw.Start();

            Hashtable table = new Hashtable();

            StreamReader sr = new StreamReader(@"C:/data.txt");
            while (!sr.EndOfStream) {
                char c = Char.ToLower((char)sr.Read());
                if (!table.Contains(c)) {
                    table.Add(c, null);
                }
            }
            sr.Close();

            foreach (char c in table.Keys) {
                Console.Write(c);
            }
            Console.WriteLine();

            sw.Stop();
            Console.WriteLine(sw.ElapsedMilliseconds);
        }
    }
}

выводит вывод

4093767
mytojevqlgbxsnidhzupkfawr
c
889
Press any key to continue . . .

Первая строка выводит количество байтов в C:/data.txt (454,863 * (7 + 2) = 4 093 767 байт). Следующие две строки вывода - это уникальные символы в C:/data.txt (включая новую строку). Последняя строка выводит количество миллисекунд, которое код должен выполнить на Pentium 4. 2.80 ГГц.

Ответ 18

Быстрое и грязное решение с использованием grep (при условии, что имя файла является "файлом" ):

for char in a b c d e f g h i j k l m n o p q r s t u v w x y z; do 
    if [ ! -z "`grep -li $char file`" ]; then 
        echo -n $char; 
    fi; 
done; 
echo

Я мог бы сделать его одним лайнером, но просто хочу, чтобы его стало легче читать.

(EDIT: забыли -i переключиться на grep)

Ответ 19

Хорошо, мой друг, я думаю, это то, что вы имели в виду... По крайней мере, это версия python!!!

f = open("location.txt", "r") # open file

ll = sorted(list(f.read().lower())) #Read file into memory, split into individual characters, sort list
ll = [val for idx, val in enumerate(ll) if (idx == 0 or val != ll[idx-1])] # eliminate duplicates
f.close()
print "Unique Characters: {%s}" % "".join(ll) #print list of characters, carriage return will throw in a return

Он не выполняет итерацию по каждому персонажу, он относительно короткий. Вы не захотите открыть с ним 500-мегабайтный файл (в зависимости от вашей памяти), но для более коротких файлов это весело:)

Я также должен добавить свою последнюю атаку!!!! Разумеется, я удалил две строки, используя стандартный ввод вместо файла, я также уменьшил активный код от 3 строк до 2. В принципе, если бы я заменил ll в строке печати выражением из строки над ним, я мог бы иметь 1 строку активного кода и одной строки импорта..... В любом случае теперь мы весело проводим:)

import itertools, sys

# read standard input into memory, split into characters, eliminate duplicates
ll = map(lambda x:x[0], itertools.groupby(sorted(list(sys.stdin.read().lower()))))
print "Unique Characters: {%s}" % "".join(ll) #print list of characters, carriage return will throw in a return

Ответ 20

Этот ответ, указанный выше, используя словарь.

Если это так, представленный там код может быть упрощен, так как Документация Python гласит:

Лучше всего думать о словаре как о неупорядоченный набор пар ключ: значение, с требованием, чтобы ключи уникальный (в пределах одного словаря).... Если вы сохраняете ключ, который уже при использовании старое значение, связанное с этот ключ забыт.

Поэтому эту строку кода можно удалить, поскольку ключи словаря всегда будут уникальными:

    if character not in letters:

И это должно сделать это немного быстрее.

Ответ 21

s=open("text.txt","r").read()
l= len(s)
unique ={}
for i in range(l):
 if unique.has_key(s[i]):
  unique[s[i]]=unique[s[i]]+1
 else:
  unique[s[i]]=1
print unique