3
\$\begingroup\$

Problem (inspired by Project Euler 29):

Consider all integer combinations of ab for X ≤ a ≤ Y and X ≤ b ≤ Y

Return a sequence of distinct terms in numerical order

  • Input is a list of 2 integers separated by a space (" "), representing the lower and upper bounds (X Y). Input is read from txt file.

  • Output is a numerically sorted list of all unique numbers generated by the function (ab) , separated by space. Output is written to txt file.

Example:

Input:  2 5
Output: 4 8 9 16 25 27 32 64 81 125 243 256 625 1024 3125

And the code:

Option Explicit On
Option Strict On
Option Infer On
Option Compare Text
Imports System
Imports System.IO
Imports System.Windows.Forms
Module ProjectEuler29

    Sub Main()
        Dim myBounds = GetInput("C:\temp\square.txt")
        Dim myResults = UseBoundsToCreateList(myBounds)
        WriteToFile("C:\temp\square-answer.txt", myResults)
    End Sub

    Private Function GetInput(ByVal inputPath As String) As Integer()
        Dim returnText As String = File.ReadAllText(inputPath)
        Dim returnArray As String() = returnText.Split(New String() {}, StringSplitOptions.None)
        Return ConvertStringToIntegerArray(returnArray)
    End Function

    Private Function ConvertStringToIntegerArray(ByVal arrayOfStrings As String()) As Integer()
        Return Array.ConvertAll(arrayOfStrings, Function(str) Int32.Parse(str))
    End Function

    Private Function UseBoundsToCreateList(ByVal myBounds As Integer()) As String
        Dim numberOfIntegers = myBounds(myBounds.Length - 1) - myBounds(0) + 1
        Dim resultList As New List(Of Double)
        Dim i As Integer
        Dim myResult As Double
        For i = myBounds(0) To myBounds(0) + numberOfIntegers - 1
            For j = myBounds(0) To myBounds(0) + numberOfIntegers - 1
                myResult = i ^ j
                If Not resultList.Contains(myResult) Then resultList.Add(myResult)
            Next
        Next
        resultList.Sort()
        Return ChangeListDblToString(resultList)
    End Function

    Private Function ChangeListDblToString(ByVal resultList As List(Of Double)) As String
        Return String.Join(" ", resultList.ToArray)
    End Function

    Private Sub WriteToFile(ByVal outputPath As String, ByVal returnData As String)
        Dim fileAuthor As New StreamWriter(outputPath)
        If Not File.Exists(outputPath) Then File.CreateText(outputPath)
        fileAuthor.WriteLine(returnData)
        fileAuthor.Close()
    End Sub

End Module
\$\endgroup\$

2 Answers 2

3
\$\begingroup\$

Use a Hashset

This seems to be a more intuitive data structure to use since you need all of your values to be unique.

The code would change very little, but you could eliminate checking if the value is already in the List.

Use built in functions before creating your own methods

When writing to a file, you shouldn't need to check if a file doesn't exist and explicitly create it. This should happen automatically.

Use the System.IO.WriteAllText method

This also closes the file automatically, freeing you from needing to do that manually. (It basically replaces the method you wrote, so you may be able to get rid of that entirely).

You've already done similar in your GetInput function by using File.ReadAllText

Only use a one line method if it increases readability

Private Function ConvertStringToIntegerArray(ByVal arrayOfStrings As String()) As Integer()
    Return Array.ConvertAll(arrayOfStrings, Function(str) Int32.Parse(str))
End Function

The above method doesn't really have a purpose. It doesn't increase readability much since the build in method explains pretty well what it does with the name ConvertAll. Of course if you feel that your method name makes your code more human readable you should use it.

\$\endgroup\$
1
\$\begingroup\$

Integers Vs Doubles

Generally speaking integers are going to be faster than floating point numbers to work with. You're building up results of doubles, do you really need to support numbers that big? You can probably get away with using Long (or Int64). Of course, as you've pointed out in your comments, Math.Pow (which is what VB uses under the hood) only operates on doubles, so you can ignore everything I've just said...

Redundancy

As I've said in my previous answer, keep an eye out for redundant code (such as your unused imports / File.Exists check).

Naming

Some of your naming could use improvement. For example:

UseBoundsToCreateList

It's not really obvious what this is doing. Use bounds to create a list of what? A better name might be:

UseBoundsToCreateListOfUniquePowerCombinations

This existing name also creates confusiong because the function takes in an a list of integers and returns a string (not a list). I'd consider changing the method so that it is responsible for taking in the bounds (lower and upper bounds as separate parameters) and then returning a sorted list of numbers satisfying the requirement (with the caller responsible for converting that list into a string if required).

Error Checking

If you're expecting input files to be in a particular format, it's often worth validating that they are as part of the read operation, so that you can handle errors correctly. I prepared an input file that instead of just having a single line, had a return at the end of the line. This confused your input processing, as it tried to convert the empty line into an integer. Checking if the right number of entries were in the returned array would have given the program the opportunity to tell the user what went wrong. The easiest way to fix this specific problem would be to change the Split call to remove empty entries:

Dim returnArray As String() = returnText.Split(New String() {},
                                               StringSplitOptions.RemoveEmptyEntries)
\$\endgroup\$
2
  • \$\begingroup\$ The power operation said it returns a double - should I convert that to an integer and use an integer instead? \$\endgroup\$ Sep 19, 2016 at 13:53
  • \$\begingroup\$ @Raystafarian No, I'd leave them as doubles, my mistake. It occurred to me as I left the keyboard that it might be the case and then slipped my mind before I got back to it. I was also a bit concerned that doubles might lose some precision that could cause issues, however this also doesn't seem to be the case, so I would just stick with doubles. \$\endgroup\$
    – forsvarir
    Sep 19, 2016 at 14:58

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.