user19267668
user19267668

Reputation:

Julia Bit-by-Bit Exercises 4 -16

I'm new to Julia Language and, by now, trying to learn by myself using the book "Julia Bit-by-Bit: Programming for Beginners" wrote by Noel Kalicharan. Right now I'm trapped in Problem 16 - Exercises 4, which asks for a solution using 'for', 'if', 'while' to the next problem:

You are given a file containing an unknown amount of numbers. Each number is one of the numbers 1 to 9. A number can appear zero or more times and can appear anywhere in the file. Some sample data are:

5 3 7 7 7 4 3 3 2 2 2 6 7 4 7 7

2 2 9 6 6 6 6 6 8 5 5 3 7 9 9 9

Write a program to read the data once and print the number which appears the most in consecutive positions and the number of times it appears. Ignore the possibility of a tie. For the above data, output should be 6 5.

Can anyone help me?

Thanks!

Upvotes: 0

Views: 216

Answers (3)

user19267668
user19267668

Reputation:

I just solved it. I appreciate your to time for answering my question. In your answers there is some code that I'm not familiar yet. So I take these days to think and try to figure it out using the tools that the book provide me.

function exercise16()
    inn = open("input.txt", "r")
    
    n = 0
    maxn = 0
    maxdigit = ""

    while (eData = readline(inn)) != ""
        eData = split(eData)

        for i in "123456789"
            while true
                n += 1
                if i != eData
                    break
                end
            end
            if n > maxn
                maxn = n
                maxdigit = i
                n = 0
                continue
            end
        end
    end
    print("$maxdigit $maxn")
    close(inn)
end

Upvotes: 0

AboAmmar
AboAmmar

Reputation: 5559

This turned out to be harder than I initially thought, so I gave it a try. First you read the contents of the file containing the digits and remove spaces. Then, initialize the frequency of repetition to zeros and start from second digit. If a digit is equal to the previous one, increment its count and continue until all digits were compared. Finally return the digit with the maximum count and its count.

function calc_freq(file_path)
    freq = Dict(zip('0':'9',fill(0,10))) # digits and their frequencies 
    str = read(file_path, String)        # read whole file as String
    str = filter(!isspace, str)          # remove possible spaces

    i = 1 
    c = str[1]
    while i < length(str)
        count = 1
        for j = i+1:length(str)
            if str[j] == c
                count += 1
            else
                break
            end
        end
        if count > 1
            freq[c] = max(count, freq[c])
        end
        i += count
        c = str[i] 
    end
    maxval = maximum(values(freq))
    for (k,v) in freq 
        v == maxval && return (k,v)
    end
end

If applied on your example input, this outputs:

('6', 5)

Edit: Inspired by @SundarR's answer, I optimized my original version so that it keeps track of only one longest repetitive sequence instead of all the sequences of all ten digits, which was not required by the question. This version is 40X faster than @SundarR's version. The price here is higher memory usage, but for 40X speed difference, that's a good price to pay.

function calc_freq_fast(file_path)
    str = read(file_path, String)  # read file contents as String
    str = filter(!isspace, str)    # remove possible spaces
    digit = maxdigit = '\0'
    count = maxcount = 0
    for ch in str
        if ch == digit
            count += 1
        else
            digit = ch 
            count = 1
        end
        if count > maxcount
            maxdigit, maxcount = digit, count
        end
    end
    maxdigit, maxcount
end

This is how the two methods compare on a 100k digits file:

@btime getmaxrepeater("file.txt")  # 19.952 ms (11 allocations: 680 bytes)
@btime calc_freq_fast("file.txt")  # 495.600 μs (15 allocations: 391.66 KiB)

Upvotes: 0

Sundar R
Sundar R

Reputation: 14695

Since the question says "a file containing an unknown amount of numbers", I wanted to avoid assuming that the whole file is small enough to be read into memory. So instead, this code reads only a single character at a time, skipping past any non-numeric characters in the file.

"""
    getmaxrepeater([filename::String])

Given a file, find the digit that repeats the most consecutive times in it.

Returns the most repetitive digit (as a Char) and the number of times it
repeats. If no numeric characters are found in the file, returns ('\0', 0). 
"""
function getmaxrepeater(fname = joinpath(@__DIR__, "data/repeatingnums.txt"))
  currcount = maxcount = 0
  currdig = maxdig = '\0'
  f = open(fname)
  while true
    # Skip any characters that are not one of the digits we want
    skipchars(!isnumeric, f)
    # Try to read a single character (a digit) from the file
    c = try
      read(f, Char)
    catch e
      # End-Of-File (EOFError) is expected when file contents are done, but any
      # other error should be rethrown and handled by Julia
      e isa EOFError || rethrow()

      # If it is the expected EOFError, close the filehandle and return the results
      close(f)
      return (maxdig, maxcount)
    end
    # If the digit we just read is a repeat of the previous one, just increase its count
    if c == currdig
      currcount += 1
    else # otherwise, start counting the new one
      currdig = c
      currcount = 1
    end
    # Update the maxcount (and the corresponding digit maxdig) every time the
    # old maxcount is exceeded
    if currcount > maxcount
      maxdig, maxcount = currdig, currcount
    end
  end
end

julia> getmaxrepeater("./data/repeatingnums.txt")
('6', 5)

Upvotes: 0

Related Questions