我有一个包含450,000多行条目的文件。每个条目的长度约为7个字符。我想知道的是这个文件的独特字符。
例如,如果我的文件是以下内容;
Entry ----- Yabba Dabba Doo
然后结果将是
独特字符:{abdoy}
注意我不关心案例,也不需要订购结果。有些东西告诉我这对Linux人来说很容易解决。
我正在寻找一种非常快速的解决方案。我真的不想创建代码来遍历每个条目,遍历每个字符......等等。我正在寻找一个很好的脚本解决方案。
通过快速,我的意思是快速实施......不一定快速运行。
答案 0 :(得分:16)
BASH shell脚本版本(无sed / awk):
while read -n 1 char; do echo "$char"; done < entry.txt | tr [A-Z] [a-z] | sort -u
更新:只是为了它,因为我很无聊并且还在考虑这个问题,这里是一个使用set的C ++版本。如果运行时间很重要,这将是我推荐的选项,因为C ++版本需要稍微超过半秒来处理具有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),这是一个示例运行时间:
[user@host]$ g++ -o unique_chars unique_chars.cpp
[user@host]$ time ./unique_chars < chars.txt
a
b
d
o
y
real 0m0.638s
user 0m0.612s
sys 0m0.017s
答案 1 :(得分:10)
根据要求,一个纯shell脚本“解决方案”:
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
答案 2 :(得分:6)
使用set
数据结构。大多数编程语言/标准库都有一种或另一种。如果他们不这样做,请使用哈希表(或通常,字典)实现,只省略值字段。使用您的角色作为键。这些数据结构通常会过滤掉重复的条目(因此名称为set
,来自其数学用法:集合没有特定的顺序,只有唯一的值。)
答案 3 :(得分: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
中唯一可打印字符的列表。
答案 4 :(得分:4)
以下是 PowerShell 示例:
gc file.txt | select -Skip 2 | % { $_.ToCharArray() } | sort -CaseSensitive -Unique
产生:
d
ÿ
一个
b
o
我喜欢它很容易阅读。
编辑:这是一个更快的版本:
$letters = @{} ; gc file.txt | select -Skip 2 | % { $_.ToCharArray() } | % { $letters[$_] = $true } ; $letters.Keys
答案 5 :(得分:3)
s = open("data.txt", "r").read()
print "Unique Characters: {%s}" % ''.join(set(s))
Python w / sets(输出更好)
import re
text = open("data.txt", "r").read().lower()
unique = re.sub('\W, '', ''.join(set(text))) # Ignore non-alphanumeric
print "Unique Characters: {%s}" % unique
答案 6 :(得分:2)
算法: {(3}}将文件存入内存。
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.
答案 7 :(得分:2)
一个非常快速的解决方案是制作一个小型C程序,读取其标准输入,进行聚合并吐出结果。
为什么你需要一个“脚本”的任意限制呢?
无论如何,剧本究竟是什么?
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 :(得分:1)
cat yourfile |
perl -e 'while(<>){chomp;$k{$_}++ for split(//, lc $_)}print keys %k,"\n";'
答案 9 :(得分:1)
使用bash的替代解决方案:
sed "s/./\l\0\n/g" inputfile | sort -u | grep -vc ^$
编辑抱歉,我实际上误读了这个问题。上面的代码计算唯一字符。最后省略c
切换显然可以解决问题但是,这个解决方案对saua没有任何实际优势(特别是因为他现在使用相同的sed
模式而不是显式捕获)。
答案 10 :(得分:1)
虽然不是脚本,但这个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, {, |, }]
答案 11 :(得分:0)
import codecs
file = codecs.open('my_file_name', encoding='utf-8')
# Runtime: O(1)
letters = set()
# Runtime: O(n^2)
for line in file:
for character in line:
letters.add(character)
# Runtime: O(n)
letter_str = ''.join(letters)
print(letter_str)
另存为unique.py
,然后以python unique.py
运行。
答案 12 :(得分:0)
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
答案 13 :(得分:0)
上面提到的answer使用字典。
如果是这样,那里提供的代码可以简化一点,因为Python documentation状态:
最好将字典视为 一组无序的键:值对, 要求密钥是 独特的(在一个字典中)....如果 使用已经存在的密钥存储 在使用中,与之相关的旧值 那把钥匙被遗忘了。
因此,可以删除此行代码,因为字典键始终是唯一的:
if character not in letters:
这应该会让它快一点。
答案 14 :(得分:0)
老问题,我知道,但这里有一个快速的解决方案,这意味着它运行得很快,如果你知道如何复制/粘贴,它的编码速度也可能相当快;)
背景 我有一个巨大的 csv 文件(12 GB,134 万行,127.2 亿个字符),我正在将它加载到 postgres 中,但由于其中包含一些“坏”字符而失败,所以很自然地我试图找到一个不在其中的字符我可以用作引号字符的文件。
我从 @jay's C++ answer 开始:
(注意:所有这些代码示例都是用 g++ -O2 uniqchars.cpp -o uniqchars
编译的)
#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;
}
时间:
real 10m55.026s
user 10m51.691s
sys 0m3.329s
我认为一次将整个文件读入内存会比所有对 cin.get()
的调用更有效。这将运行时间减少了一半以上。
(我还添加了一个文件名作为命令行参数,并使其打印出由空格而不是换行符分隔的字符)。
#include <set>
#include <string>
#include <iostream>
#include <fstream>
#include <iterator>
int main(int argc, char **argv) {
std::set<char> seen_chars;
std::set<char>::const_iterator iter;
std::ifstream ifs(argv[1]);
ifs.seekg(0, std::ios::end);
size_t size = ifs.tellg();
fprintf(stderr, "Size of file: %lu\n", size);
std::string str(size, ' ');
ifs.seekg(0);
ifs.read(&str[0], size);
/* ignore whitespace and case */
for (char& ch : str) {
if (!isspace(ch)) {
seen_chars.insert(tolower(ch));
}
}
for(iter = seen_chars.begin(); iter != seen_chars.end(); ++iter) {
std::cout << *iter << " ";
}
std::cout << std::endl;
return 0;
}
时间:
real 4m41.910s
user 3m32.014s
sys 0m17.858s
isspace()
检查和 tolower()
除了 set insert 之外,isspace()
和 tolower()
是 for 循环中唯一发生的事情,所以我想我会删除它们。又缩短了 1.5 分钟。
#include <set>
#include <string>
#include <iostream>
#include <fstream>
#include <iterator>
int main(int argc, char **argv) {
std::set<char> seen_chars;
std::set<char>::const_iterator iter;
std::ifstream ifs(argv[1]);
ifs.seekg(0, std::ios::end);
size_t size = ifs.tellg();
fprintf(stderr, "Size of file: %lu\n", size);
std::string str(size, ' ');
ifs.seekg(0);
ifs.read(&str[0], size);
for (char& ch : str) {
// removed isspace() and tolower()
seen_chars.insert(ch);
}
for(iter = seen_chars.begin(); iter != seen_chars.end(); ++iter) {
std::cout << *iter << " ";
}
std::cout << std::endl;
return 0;
}
最终版本的时间:
real 3m12.397s
user 2m58.771s
sys 0m13.624s
答案 15 :(得分:0)
好吧,我的朋友,我想这就是你的想法....至少这是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 MB的文件(取决于您的RAM),但对于较短的文件,这很有趣:)
我还要加上我的最后一次攻击!!!!不可否认,我通过使用标准输入而不是文件消除了两行,我还将活动代码从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
答案 16 :(得分:0)
simple solution from @Triptych 已经帮助了我(我的输入是一个 124 MB 大小的文件,因此这种将整个内容读入内存的方法仍然有效)。
但是,我遇到了编码问题,python 没有正确解释 UTF8 编码的输入。所以这里有一个稍微修改过的版本,它适用于 UTF8 编码的文件(并对输出中收集的字符进行排序):
import io
with io.open("my-file.csv",'r',encoding='utf8') as f:
text = f.read()
print "Unique Characters: {%s}" % ''.join(sorted(set(text)))
答案 17 :(得分:0)
使用grep的快速和脏解决方案(假设文件名是“file”):
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
我本可以把它变成单行,但只是想让它更容易阅读。
(编辑:忘了-i切换到grep)
答案 18 :(得分:0)
其中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
中的唯一字符(包括换行符)。最后一行输出告诉你代码在2.80 GHz奔腾4上执行的毫秒数。
答案 19 :(得分:0)
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;
}
答案 20 :(得分:0)
Python使用字典。我不知道为什么人们如此依赖集合或列表来保存东西。一个集合可能比字典更有效。但是两者都应该花费一些时间来访问项目。并且两个围绕列表运行圆圈,在该列表中,您搜索列表中的每个字符,以查看该字符是否已在列表中。 Lists和Dictionaries也是用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()) + "}"
答案 21 :(得分:0)
使用JSDB Javascript(包括Firefox浏览器中的javascript引擎)试用此文件:
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(''));
答案 22 :(得分:0)
不使用集合的Python。
file = open('location', 'r')
letters = []
for line in file:
for character in line:
if character not in letters:
letters.append(character)
答案 23 :(得分:0)
在c ++中,我首先遍历字母表中的字母然后在每个字符串上运行strchr(),并将文件作为字符串。这将告诉您该信件是否存在,然后将其添加到列表中。