Trova parole comuni in una stringaCIAO,
Ho il seguente codice jsl che stampa le parole comuni e il conteggio. Tuttavia, non sembra che lo stia contando correttamente.
L'output che ottengo è:
parolecomuni = ["c1" => 3, "cate" => 3];
Dovrebbe essere
parolecomuni = ["c1" => 3, "cate" =>3, "shotp" => 3];
Avete suggerimenti?
input = "CATE_N_C1_Shotp,CATE_P_C1_Shotp,CATE_P_C1_Shotp";// input string<BR />
// Define boundary characters as _ and ,
boundaryChars = "_,";
// Define the pattern for boundary and word
boundaryPat = Pat Any( boundaryChars ) | Pat Pos( 0 );
wordPat = Pat Break( boundaryChars ) | Pat Rem();
patMatchWord = boundaryPat + Pat Pos()>>position + wordPat>>word + boundaryPat;
// Associative array to count word frequency
wordsToCount = [=>];
// Match pattern in the input
rc = Pat Match( input, patMatchWord
+ Pat Test(
word = Lowercase( word ); // Convert word to lowercase for uniformity
If( Contains( wordsToCount, word ),
wordsToCount[word] = wordsToCount[word] + 1,
wordsToCount[word] = 1
);
)
+ Pat R Pos( 0 ) // The pattern must reach the end
);
// Identify common words (those that appear in all elements)
elements = Words( input, "," );
totalElements = N Items( elements );
commonWords = [=>];
For Each( {{word, count}}, wordsToCount,
If( count == totalElements,
commonWords[word] = count
);
);
// Display the common words and their counts
Show( commonWords );<BR /><BR />// commonWords = ["c1" => 2, "cate" => 2];Grazie
Automazione e scriptingRe: Trova parole comuni in una stringaBene! Alcune modifiche, spiegate di seguito.
input = "CATE_N_C1_Shotp,CATE_P_C1_Shotp,CATE_P_C1_Shotp";// input string
// Define boundary characters as _ and ,
boundaryChars = "_,";
// Associative array to count word frequency
wordsToCount = [=> ];
// Match pattern in the input
rc = Pat Match(
Lowercase( input ) || boundaryChars, // pre-normalize and add sentinel at end
Pat Pos( 0 )
+ Pat Repeat(
Pat Break( boundaryChars ) >> word + Pat Span( boundaryChars )
+ Pat Test(
If( Contains( wordsToCount, word ),
wordsToCount[word] = wordsToCount[word] + 1,
wordsToCount[word] = 1
);
1; // explicitly, result of pattest is 'true'
)
)
+ Pat R Pos( 0 ) // The pattern must reach the end
);
// Identify common words (those that appear in all elements)
elements = Words( input, "," );
totalElements = N Items( elements );
commonWords = [=> ];
For Each( {{word, count}}, wordsToCount, If( count == totalElements, commonWords[word] = count ) );
// Display the common words and their counts
Show( commonWords );// commonWords = ["c1" => 3, "cate" => 3, "shotp" => 3];
;
La modifica principale consiste nell'usare PatRepeat per scorrere l'input un token (parola) alla volta e aggiungere un separatore sentinella alla fine. Il tuo codice originale scorre la stringa cercando di trovare una corrispondenza con una sola parola, quindi scopre che la parola non è alla fine della stringa, avanzando l'inizio della corrispondenza di un carattere e cercando di trovare di nuovo una corrispondenza. Manca lo "shotp" finale perché non c'è un separatore finale. Il lavoro in pattest è semplificato dalla pre-minuscolatura nello stesso momento in cui viene aggiunta la sentinella.
Sono abbastanza sicuro che qualcuno proporrà una soluzione utilizzando la funzione words(), che non avrà bisogno di una sentinella.
modifica: in qualche modo mi è sfuggita questa sentinella del passato .
Re: Trova parole comuni in una stringaPuoi anche utilizzare le tabelle JMP
Names Default To Here(1);
input = "CATE_N_C1_Shotp,CATE_P_C1_Shotp,CATE_P_C1_Shotp";
input = lowercase(input);
elements = Words(input, ",");
dt = New Table("Data",
New Column("Word", Character, Nominal),
New Column("Elementnr", Numeric, Nominal),
private
);
For Each({element, idx}, elements,
l = Words(element, "_");
nr = Repeat(idx, N Items(l));
r = N Rows(dt);
dt << Add Rows(N Items(l));
dt[r+1::r+N Items(l), 1] = l;
dt[r+1::r+N Items(l), 2] = nr;
);
dt_summary = dt << Summary(
Group(:Word),
N,
Subgroup(:Elementnr),
Freq("None"),
Weight("None"),
Link to original data table(0),
private
);
sums = V Sum((dt_summary[0, 3::N Cols(dt_summary)] > 0)`);
valid_idx = Loc(sums >= N ITems(elements));
words = Associative Array(dt_summary[valid_idx, 1], dt_summary[valid_idx, 2]);
Close(dt, no save);
Close(dt_summary, no save);
show(words);
Ci sono anche alcune piccole ottimizzazioni che potrebbero essere fatte se necessario
Re: Trova parole comuni in una stringa@Craige_Hales Un'altra domanda: è possibile mantenere l'ordine delle parole?
parolecomuni = ["c1" => 3, "cate" => 3, "shotp" => 3];
Dovrebbe essere
CATE_N_C1_Shotp
parolecomuni = ["cate" => 3, "c1" => 3, "shotp" => 3];
Re: Trova parole comuni in una stringa@jthi è possibile mantenere l'ordine delle parole?
Dovrebbe essere: parole = ["cate" => 3, "c1" => 3, "shotp" => 3];
Re: Trova parole comuni in una stringaForse.
input = "CATE_N_C1_Shotp,CATE_P_C1_Shotp,CATE_P_C1_Shotp";// input string
// Define boundary characters as _ and ,
boundaryChars = "_,";
position = 0;
wordToPosition = [=> ];
// Associative array to count word frequency
wordsToCount = [=> ];
// Match pattern in the input
rc = Pat Match(
Lowercase( input ) || boundaryChars, // pre-normalize and add sentinel at end
Pat Pos( 0 )
+ Pat Repeat(
Pat Break( boundaryChars ) >> word + Pat Span( boundaryChars ) >> sep
+ Pat Test(
position += 1;
If( Contains( wordsToCount, word ),
wordsToCount[word] = wordsToCount[word] + 1,
wordsToCount[word] = 1
);
If( Contains( wordToPosition, word ) & wordToPosition[word] != position,
throw("word ordering not consistent")
);
wordToPosition[word] = position;
if(sep==",", position = 0);
1; // explicitly, result of pattest is 'true'
)
)
+ Pat R Pos( 0 ) // The pattern must reach the end
);
// Identify common words (those that appear in all elements)
elements = Words( input, "," );
totalElements = N Items( elements );
commonWords = [=> ];
For Each( {{word, count}}, wordsToCount, If( count == totalElements, commonWords[word] = count ) );
// Display the common words and their counts
Show( commonWords );// commonWords = ["c1" => 3, "cate" => 3, "shotp" => 3];
Show( wordToPosition );// wordToPosition = ["c1" => 3, "cate" => 1, "n" => 2, "p" => 2, "shotp" => 4];
keys = wordToPosition << getkeys;//{"c1", "cate", "n", "p", "shotp"}
vals = wordToPosition << getvalues;// {3, 1, 2, 2, 4}
sort = Rank( vals );// [2, 3, 4, 1, 5]
keys = keys[sort];// {"cate", "n", "p", "c1", "shotp"}
vals = vals[sort];// {1, 2, 2, 3, 4}
For Each( {k}, keys, If( Contains( commonWords, k ), Show( k, commonWords[k] ) ) );
/*
k = "cate";
commonWords[k] = 3;
k = "c1";
commonWords[k] = 3;
k = "shotp";
commonWords[k] = 3;
*/
La funzione throw() potrebbe segnalare un potenziale problema.
Re: Trova parole comuni in una stringaPuò. Con un solo esempio di dati è un po' fastidioso cercare di capire cosa si dovrebbe fare. Ad esempio, la stessa parola può apparire più volte nello stesso elemento? E l'ordine può cambiare all'interno degli elementi?
Re: Trova parole comuni in una stringaNaturalmente, se hai bisogno di un array associativo, non puoi ordinarlo in nessun altro modo se non in quello che fa JMP, MA puoi ordinare i valori che ne ricavi utilizzando i ranghi.
Cercando di mantenere la soluzione "jmp table" (ho fatto poche ipotesi)
Names Default To Here(1);
input = "CATE_N_C1_Shotp,CATE_P_C1_Shotp,CATE_P_C1_Shotp";
input = lowercase(input);
elements = Words(input, ",");
dt = New Table("Data",
New Column("Word", Character, Nominal),
New Column("Elementnr", Numeric, Nominal)
);
For Each({element, idx}, elements,
l = Words(element, "_");
nr = Repeat(idx, N Items(l));
r = N Rows(dt);
dt << Add Rows(N Items(l));
dt[r+1::r+N Items(l), 1] = l;
dt[r+1::r+N Items(l), 2] = nr;
);
new_col1 = dt << New Column("C", Numeric, Continuous, Formula(
Col Number(:Elementnr, :Word)
));
new_col2 = dt << New Column("R", Numeric, Continuous, Formula(
Col Min(Col Cumulative Sum(1, :Elementnr), :Word)
));
dt << run formulas;
new_col1 << delete formula;
new_col2 << delete formula;
Summarize(dt, elem = by(:Elementnr));
element_count = N Items(elem);
dt << Delete Rows(dt << get rows where(:C != element_count));
dt << Select Duplicate Rows(Match(:Word)) << Delete Rows << Clear Select;
aa = Associative Array(:Word, :C); // results in AA
r = Rank(:Word << get values); // use Rank to return in original order
Close(dt, No save);
keys = (aa << get keys)[r];
// Values does not need sorting as they always have same values
values = aa << get values;
Write();
show(aa, r, keys, values);