2
votes

Good evening, I have the following list:

        lf <- 1 / 100 * c(
  A = 6.756, B = 1.234, C = 2.302, D = 3.518, E = 10.508, F = 1.843, G = 1.667,
  H = 5.041, I = 5.763, J = 0.127, K = 0.639, L = 3.330, M = 1.990, N = 5.583,
  O = 6.210, P = 1.596, Q = 0.079, R = 4.953, S = 5.234, T = 7.492, U = 2.282,
  V = 0.809, W = 1.952, X = 0.124, Y = 1.633, Z = 0.061, ` ` = 17.272)

and a text:

text <- c("THIS IS A TEST")

I am trying to write a loop so that each letter in text receives the right above number from lf. I want it to be stored in a matrix so that after applying a function I can find the highest value.

I started with

  n <- length(lf)
mat <- matrix(ncol=2, nrow=n)

for (i in 1:n) {

  var1[[i]] <- 

}

but i don't seem to be able to get my head around this problem. How do I write a function that goes through the values of a list (lf) and stores each calculated value in a matrix?

Help is very much appreciated =)

The numbers above represent the log likelihood (its a cyphering problem). I am to find the lowest sum of all likelihoods which a letter (i.e. "K") would give when trying to decypher a code that was cyphered with one letter.

I have found out how to get the sum for a given text (including spaces)

sum(log(letterfrequencies[match(plaintext, names(letterfrequencies))]))

Now I have to find the lowest log likelihood when trying every single letter on a cyphered text for which I thought i needed a loop to try out every single letter

(I deleted my previous question since I didnt explain the problem properly)

2
Do you need the sum for all LETTERS in alphabet - akrun

2 Answers

2
votes

You can do this without a loop:

sapply(strsplit(text, ""), function(x) lf[x])
#>      [,1]
#> T 0.07492
#> H 0.05041
#> I 0.05763
#> S 0.05234
#>   0.17272
#> I 0.05763
#> S 0.05234
#>   0.17272
#> A 0.06756
#>   0.17272
#> T 0.07492
#> E 0.10508
#> S 0.05234
#> T 0.07492

If you just want to sum the values of a single letter, a little wrapper function should do the trick:

sum_letters <- function(letter, text) {
  sum(strsplit(text, "")[[1]] %in% letter) * lf[letter]
}

This allows you to do:

sum_letters("T", text)
#>       T 
#> 0.22476

Or get the sums for all letters in the alphabet:

sums <- sapply(LETTERS, sum_letters, text = text, USE.NAMES = FALSE)

sums
#>       A       B       C       D       E       F       G       H       I       J 
#> 0.06756 0.00000 0.00000 0.00000 0.10508 0.00000 0.00000 0.05041 0.11526 0.00000 
#>       K       L       M       N       O       P       Q       R       S       T 
#> 0.00000 0.00000 0.00000 0.00000 0.00000 0.00000 0.00000 0.00000 0.15702 0.22476 
#>       U       V       W       X       Y       Z 
#> 0.00000 0.00000 0.00000 0.00000 0.00000 0.00000

and thereby find the best fit:

which.max(sums)
#>  T 
#> 20

Created on 2020-11-01 by the reprex package (v0.3.0)

2
votes

We can use matrix directly

as.matrix( lf[regmatches(text, gregexpr('[A-Z ]', text))[[1]]])

-output

#    [,1]
#T 0.07492
#H 0.05041
#I 0.05763
#S 0.05234
#  0.17272
#I 0.05763
#S 0.05234
#  0.17272
#A 0.06756
#  0.17272
#T 0.07492
#E 0.10508
#S 0.05234
#T 0.07492

If we need a group by sum

v1 <- lf[regmatches(text, gregexpr('[A-Z ]', text))[[1]]]
tapply(v1, names(v1), FUN = sum)
#          A       E       H       I       S       T 
#0.51816 0.06756 0.10508 0.05041 0.11526 0.15702 0.22476 

If we need to include all the LETTERS

sapply(split(v1, factor(names(v1), levels = LETTERS)), sum)
#      A       B       C       D       E       F       G       H       I       J       K       L       M       N       O       P 
#0.06756 0.00000 0.00000 0.00000 0.10508 0.00000 0.00000 0.05041 0.11526 0.00000 0.00000 0.00000 0.00000 0.00000 0.00000 0.00000 
#      Q       R       S       T       U       V       W       X       Y       Z 
#0.00000 0.00000 0.15702 0.22476 0.00000 0.00000 0.00000 0.00000 0.00000 0.00000