|
|||||||
|
|
|
![]() |
|
|
Strumenti |
|
|
#1 |
|
Senior Member
Iscritto dal: May 2004
Città: Londra (Torino)
Messaggi: 3692
|
[Tutti] Contest: T9 lookalike
Si vuole costruire una delle parti "Core" di un HID (Human Interface Device) che utilizza il T9
il concetto del T9 e' che, avendo una tastiera con pochi tasti, si vuole offrire all'utente la possibilita' di comporre in modo semplice tutte le parole possibili. I tasti in questione sono 9 (in realta' per il nostro esercizio sono solo 8) Con la seguente associazione statica e data a priori. 1 -> Nulla 2 -> abc 3 -> def 4 -> ghi 5 -> jkl 6 -> mno 7 -> prqs 8 -> tuv 9 -> wxyz Si ha a dispozione un dizionario di parole dato, con tante parole, alcune corte, alcune lunghe, alcune lunghissime. Lunghezza indefinita, ma volendo anche piu' lunghe di 50 caratteri, dato che si vuole a priori supportare anche lingue come il tedesco, con lunghezza indefinita delle parole, e magari anche qualche applicazione crittografica, dove le password possono appunto anche essere indefinitamente lunghe. Si ottiene in ingresso un numero, es: 2426 Scopo dell'esercizio e' quello di restituire in output tutte le parole del nostro dizionario che possono essere ricondotte al numero in questione. Supponendo in ingresso un dizionario/enciclopedia italiano, un output probabile potra' essere: bico ciao cibo cico In modo ovviemente veloce, ovvero con possibilmente un algoritmo ottimale o quasi. La soluzione deve essere semplicemente scalabile, nel senso che all'aumentare del numero di parole del dizionario la ricerca dell'output non deve peggiorare (troppo). Un assunto che si puo' fare, ma che non deve essere vincolante, e' che ad un numero composto da tante cifre e' probabile che corrispondano meno parole reali, e viceversa, ma non e' detto che siano comunque per forza una sola. Qui l'elenco delle parole italiane da supportare. Come detto, la lunghezza di una parola potrebbe essere a priori anche molto lunga. http://www.yorku.ca/lbianchi/italian.../italia-1a.zip Aprite, leggete, capite e parsate come vi pare. Presto arrivera' anche l'elenco dei valori numerici target di cui poi trovare le corrispondenze.
__________________
Se pensi che il tuo codice sia troppo complesso da capire senza commenti, e' segno che molto probabilmente il tuo codice e' semplicemente mal scritto. E se pensi di avere bisogno di un nuovo commento, significa che ti manca almeno un test. |
|
|
|
|
|
#2 |
|
Senior Member
Iscritto dal: Oct 2006
Città: milano
Messaggi: 1439
|
Bello
|
|
|
|
|
|
#3 |
|
Senior Member
Iscritto dal: Feb 2006
Messaggi: 1304
|
Aggiungerei anche che visto l'obiettivo del programma, non bisogna ottimizzare il caso della ricerca di "2426" ma più che altro la ricerca del nuovo gruppo dato il vecchio gruppo e la nuova cifra
|
|
|
|
|
|
#4 |
|
Senior Member
Iscritto dal: Sep 2009
Città: Nel mondo dei sogni
Messaggi: 4131
|
Questo è interessante
|
|
|
|
|
|
#5 |
|
Senior Member
Iscritto dal: Jul 2005
Città: Bologna
Messaggi: 1130
|
Ho tirato fuori questa schifezza in C++... però è limitato, perchè non tira fuori match parziali (bico, cico, nell'esempio) ma solo match completi.
Spero di vedere soluzioni più furbe della mia edit: è un pò "convoluted", ma adesso dovrebbe stampare anche i match parziali... Continuo a sperare in soluzioni migliori Codice:
martind@b0x:~/src/random/contest-t9$ cat > t9.cpp
#include <iostream>
#include <algorithm>
#include <iterator>
#include <map>
#include <string>
#include <fstream>
#include <sstream>
#include <set>
inline std::string int_to_string(int n) {
std::stringstream ss;
ss << n;
return ss.str();
}
struct t9bot {
std::map<char, std::string> keyboard;
std::multimap<std::string, std::string> candidates;
t9bot() {
const std::string chars[] = {"abc","def","ghi","jkl","mno","pqrs","tuv","wxyz"};
for (int i = 0; i < 8; ++i)
for (size_t j = 0; j < chars[i].length(); ++j)
keyboard[chars[i][j]] = int_to_string(i+2);
}
inline void operator()(const std::string word) {
std::string key;
for (size_t i = 0; i < word.length(); ++i) key += keyboard[word[i]];
candidates.insert(std::pair<std::string, std::string>(key, word));
}
void print_solutions(const std::string key) {
typedef std::multimap<std::string, std::string>::iterator map_iterator;
map_iterator low = candidates.lower_bound(key);
map_iterator high = candidates.upper_bound(key+"9");
std::set<std::string> solution_set;
for (map_iterator it = low; it != high; ++it)
solution_set.insert(it->second.substr(0, key.length()));
for (std::set<std::string>::iterator it = solution_set.begin();
it != solution_set.end(); ++it)
std::cout << *it << std::endl;
}
};
int main(int argc, char **argv) {
t9bot bot;
std::ifstream dictionary(argc > 1 ? argv[1] : "dictionary");
bot = std::for_each(
std::istream_iterator<std::string>(dictionary),
std::istream_iterator<std::string>(), bot);
while (std::cin.good()) {
std::string test;
std::cin >> test;
if (!test.empty()) bot.print_solutions(test);
}
return 0;
}
martind@b0x:~/src/random/contest-t9$ g++ -Wall -O2 t9.cpp -o t9
martind@b0x:~/src/random/contest-t9$ echo 2426 | ./t9 dict
agam
bian
bico
cham
chan
ciam
cian
ciao
cibo
cico
martind@b0x:~/src/random/contest-t9$
__________________
-> The Motherfucking Manifesto For Programming, Motherfuckers Ultima modifica di shinya : 07-07-2010 alle 00:03. |
|
|
|
|
|
#6 |
|
Senior Member
Iscritto dal: Oct 2006
Città: Roma
Messaggi: 1383
|
propongo un'idea per migliorare la versione che fa solo match completi: partendo dal dizionario é possibile creare una hash table dove le chiavi sono le sequenze numeriche necessarie per comporre le parole e i valori sono le liste delle parole che possono essere composte con una certa sequenza numerica; per esempio in questa hash table alla chiave 2426 sará contenuta una lista di due elementi, "cibo" e "ciao".
se N é il numero di parole del dizionario il tempo necessario per costruire questa hash table é O(N) e lo spazio anche (quindi, in particolare, lo spazio occupato resta asintoticamente identico). i vantaggi sono evidenti perché la hash table la si costruisce una volta per tutte e poi quando la si ha si puó fare qualunque consultazione in tempo costante, ottenendo grande efficienza anche nel caso in cui le cifre arrivino sul momento. per completare l'idea non resta che pensare a un modo conveniente per memorizzare questa struttura dati in un file oltre che in memoria. purtroppo é solo un'idea e non so se avró il tempo di realizzarla T_T
__________________
3D Volley Demo (Facebook) | Reversi (Facebook) | Blockout (Facebook) | Puzzle15 (Facebook) Ultima modifica di fero86 : 06-07-2010 alle 23:32. |
|
|
|
|
|
#8 |
|
Senior Member
Iscritto dal: Oct 2006
Città: Roma
Messaggi: 1383
|
gli alberi in genere non contengono mica un solo nodo per livello... e comunque giá std::map é implementata tramite BST.
|
|
|
|
|
|
#9 |
|
Senior Member
Iscritto dal: Sep 2009
Città: Nel mondo dei sogni
Messaggi: 4131
|
|
|
|
|
|
|
#10 |
|
Senior Member
Iscritto dal: Jun 2002
Città: Dublin
Messaggi: 5989
|
Conta solo il tempo di ricerca o anche il tempo di caricamento?
EDIT: e lo 0 lo possiamo ignorare? EDIT: in più ci sono parole come "abat-jour" che non sono esclusivamente alfabetiche, le ignoriamo?
__________________
C'ho certi cazzi Mafa' che manco tu che sei pratica li hai visti mai! Ultima modifica di DanieleC88 : 07-07-2010 alle 02:31. |
|
|
|
|
|
#11 |
|
Senior Member
Iscritto dal: Jun 2005
Messaggi: 365
|
Lento a caricare ma veloce nella ricerca (più che altro veloce da scrivere
Codice:
dic=Hash.new
h=Hash.new
('a'..'r').inject(6) {|i,c| h[c.to_sym] = (i/3).to_i; i+=1;}
('s'..'y').inject(23) {|i,c| h[c.to_sym] = (i/3).to_i; i+=1;}
h[:z] = 9
#p h.inspect
File.open("merged.dic") do |f|
while line = f.gets
line.strip!
s = ""
line.split('').each do |c|
s+= h[c.to_sym].to_s
end
dic[s] ||= Array.new
dic[s] << line
end
# p dic.inspect
end
dic["2426"].each do |word|
puts word
end
dic["2777682666"].each do |word|
puts word
end
|
|
|
|
|
|
#12 | |
|
Senior Member
Iscritto dal: Feb 2006
Messaggi: 1304
|
Quote:
Quindi se scrivi "2" lui ti ritorna i sottoalberi A, B e C e scrive a, b o c. Quando poi scrivi "4" lui ritorna tutti i sottoalberi di A B C di senso compiuto (cioè, che non sono null) tra AG, AH, AI, BG, BH, BI, CG, CH, CI. Una volta che la ricerca è terminata si ha un insieme di nodi; percorrendo i nodi verso l'alto si ottengono tutte le parole (anche incomplete) cercate. In questo modo tra l'altro è possibile dare diversi pesi alle diverse parole, assegnando un peso ai nodi che compongono la parola... |
|
|
|
|
|
|
#13 | |
|
Senior Member
Iscritto dal: Oct 2007
Città: Padova
Messaggi: 4131
|
Quote:
![]() @Tommo: bella l'idea dell'albero, ci avevo pensato anche io ieri, in parte proprio per il problema della distinzione tra parole formate/parole incomplete...
__________________
As long as you are basically literate in programming, you should be able to express any logical relationship you understand. If you don’t understand a logical relationship, you can use the attempt to program it as a means to learn about it. (Chris Crawford) Ultima modifica di banryu79 : 07-07-2010 alle 09:18. |
|
|
|
|
|
|
#14 | |
|
Senior Member
Iscritto dal: Jul 2005
Città: Bologna
Messaggi: 1130
|
Quote:
Comunque sono curioso di vedere una soluzione basta sull'idea postata da Tommo... avevo anch'io in mente qualcosa di simile ma non ci sono arrivato, e quindi ho ripiegato su una soluzione più barbara
__________________
-> The Motherfucking Manifesto For Programming, Motherfuckers |
|
|
|
|
|
|
#15 | |
|
Senior Member
Iscritto dal: Apr 2000
Città: Vicino a Montecatini(Pistoia) Moto:Kawasaki Ninja ZX-9R Scudetti: 29
Messaggi: 53971
|
Quote:
|
|
|
|
|
|
|
#16 |
|
Senior Member
Iscritto dal: Dec 2005
Città: Istanbul
Messaggi: 1817
|
ma l'albero non e' completo, e contiene poche parole di quella lunghezza, per cui potrebbe essere fattibile. In ogni caso ci sono strutture dati apposite per questo scopo.
__________________
One of the conclusions that we reached was that the "object" need not be a primitive notion in a programming language; one can build objects and their behaviour from little more than assignable value cells and good old lambda expressions. —Guy Steele |
|
|
|
|
|
#17 | |
|
Senior Member
Iscritto dal: Jul 2005
Città: Bologna
Messaggi: 1130
|
Quote:
__________________
-> The Motherfucking Manifesto For Programming, Motherfuckers |
|
|
|
|
|
|
#18 |
|
Senior Member
Iscritto dal: Apr 2006
Messaggi: 22462
|
posto la mia soluzione in java.
ho usato una metodologia simile a quella proposta da Tommo (è stata la prima cosa a cui ho pensato), solo invece di puntatori ho usato delle mappe. Come diceva Cionci effettivamente usa una vagonata di memoria: usando hashMap con fattore di caricamento 0.75 ho picchi di 300 mb di ram , usando mappe basate su alberi ne uso 200. sul mio sistema la soluzione è elaborata (caricamento incluso) in 9 secondi Codice:
wizard1993@wizard1993-desktop:~/NetBeansProjects/t9/dist$ time java -jar t9.jar [agam] [bian] [bico] [cham] [chan] [ciam] [cian] [ciao] [cibo] [cico] real 0m8.239s user 0m9.621s sys 0m0.420s Codice:
/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
package t9;
import java.io.*;
import java.util.*;
/**
*
* @author wizard1993
*/
public class Main {
/**
* @param args the command line arguments
*/
public static void main(String[] args) throws FileNotFoundException{
new T9Treee().search("2426");
//System.in.read();
}
}
class T9Treee {
node root = new node("");
final String symbols = "ABCDEFGHIJKLMNOPQRDQSTUVWXYZ";
HashMap<Integer, String> reverse = new HashMap<Integer, String>();
private void initTree() {
/*2 -> abc
3 -> def
4 -> ghi
5 -> jkl
6 -> mno
7 -> prqs
8 -> tuv
9 -> wxyz*/
for (int i = 0; i < symbols.length(); i++) {
String string = symbols.charAt(i) + "";
node n = new node(string);
root.nextNodes.put(string, n);
}
reverse.put(2, "abc");
reverse.put(3, "def");
reverse.put(4, "ghi");
reverse.put(5, "jkl");
reverse.put(6, "mno");
reverse.put(7, "pqrs");
reverse.put(8, "tuv");
reverse.put(9, "wxyz");
}
private void parse() throws FileNotFoundException {
for (int i = 0; i < symbols.length(); i++) {
String fileName = "ITALIANO." + symbols.charAt(i);
Scanner input = new Scanner(new BufferedInputStream(new FileInputStream(fileName)));
while (input.hasNext()) {
String string = input.nextLine();
insert(string);
}
input.close();
}
}
private void insert(String string) {
node n = root;
String swap = "";
for (int i = 0; i < string.length(); i++) {
String c = string.charAt(i) + "";
swap += c;
node next = n.nextNodes.get(c);
if (next == null) {
next = new node(c);
}
n.nextNodes.put(c, next);
next.words.add(swap);
n = next;
}
}
private class node {
String character;
public node(String character) {
this.character = character;
}
TreeMap<String, node> nextNodes = new TreeMap<String, T9Treee.node>();
Set<String> words = new TreeSet<String>();
}
public T9Treee() throws FileNotFoundException {
initTree();
parse();
}
public void search(String seq, node n, int depth) {
if(n==null)return;
if (depth >= seq.length() && n != null) {
System.out.println(n.words);
return;
}
String possible = reverse.get(Integer.valueOf(seq.charAt(depth) + ""));
for (int i = 0; i < possible.length(); i++) {
String c = possible.charAt(i) + "";
search(seq, n.nextNodes.get(c), depth+1);
}
}
public void search(String s){
search(s, root, 0);
}
}
__________________
amd a64x2 4400+ sk939;asus a8n-sli; 2x1gb ddr400; x850 crossfire; 2 x western digital abys 320gb|| asus g1
Se striscia fulmina, se svolazza l'ammazza |
|
|
|
|
|
#19 | |
|
Senior Member
Iscritto dal: Apr 2000
Città: Vicino a Montecatini(Pistoia) Moto:Kawasaki Ninja ZX-9R Scudetti: 29
Messaggi: 53971
|
Quote:
Senza considerare che una indicizzazione completa non è necessaria. |
|
|
|
|
|
|
#20 |
|
Member
Iscritto dal: Nov 2009
Messaggi: 50
|
in che senso contiene nodi null nel mezzo?hanno detto che l'albero è composto da 26 sottoalberi e quindi le lettere dovrebbero esserci tutte.e l'indicizzazione completa perchè non è necessaria?
|
|
|
|
|
| Strumenti | |
|
|
Tutti gli orari sono GMT +1. Ora sono le: 16:40.























