Arrays reconsidered

Figure 387. Reference data one step initialization Slide presentation

Combining array allocation and value assignment:

public class Rectangle {
    private int width, height;
    private boolean hasSolidBorder;
    public Rectangle(int width, int height,
                   boolean hasSolidBorder) {
        this.width = width;
        this.height = height;
        this.hasSolidBorder = hasSolidBorder;
    }
}
final Rectangle[] rectList = new Rectangle[] {
  new Rectangle(2, 5, true),
  new Rectangle(4, 1, false)
};

exercise No. 142

Converting string arrays to HTML.

Q:

Consider an array of strings. As an example we provide a list of country names:

final String[] countries = {
        "England"
        ,"France"
        ,"Germany"
};

An application is supposed to generate the following output:

<ul>
  <li>England</li>
  <li>France</li>
  <li>Germany</li>
</ul>

Implement A class method strings2html(final String [] strings) as in:

public class Stringarray2Html {

  /**
   * Create an unordered ...
   *  ...
   */
  static public String strings2html(final String [] strings) {
    ...
    return ...;
  }
}

Do not forget to provide appropriate Javadoc method and class documentation. You may want to reconsider Figure 328, “Maven javadoc:javadoc.

Generating Javadoc HTML documentation from your project should yield a result like:

Provide appropriate unit tests covering at least:

  • An empty input array.

  • An input array containing at least two strings.

A:

exercise No. 143

Pangram checker

Q:

A pangram is a string containing all letters of a given alphabet at least once. As an example we consider the alphabet of ASCII letters {'a', 'b', ..., 'z'} ignoring case. Then the following string is a pangram:

The quick brown fox jumps over the lazy dog

Tip

  1. Like in Examinations and mark frequencies create an array of sufficient size regarding each character as an index value.

  2. According to the ASCII table all characters {'a', 'b', ..., 'z'} form a gapless sequence of integer values {97, 98,..., 122}.

  3. toCharArray() allows for de-composing a String into a corresponding array of char values.

  4. Normalize strings with respect to case using toLowerCase(...).

A:

In addition to the above regular solution we also provide an approach featuring Java streams with respect to the upcoming Software development 2 lecture:

static public boolean isPangram2(final String s) {
  return 26 == s.toLowerCase().chars()
    .filter(i -> i >= 'a' && i <= 'z')
    .distinct()
    .count();
}

exercise No. 144

Route navigation

Q:

We want to estimate the amount of time being required driving a particular route. Consider the following example:

The route above may be dissected into several legs:

  1. From starting point to motorway

  2. Motorway till through road

  3. Through road till junction

  4. Junction till destination

Each leg may have a different speed limit. We thus define:

public class Segment {

   /**
    * Indication a segment does not have any speed limit.
    */
   static public final int NO_SPEED_LIMIT = 0;

   /**
    * The distance of the current leg in km.
    */
   public final double distance;

   /**
    * The current leg's speed limit in km / h.
    */
   public final int speedLimit;

   /**
    * Creating an (immutable) leg
    * @param distance {@link #distance}
    * @param speedLimit {@link #speedLimit}
    */
   public Segment(final double distance, final int speedLimit) {
      this.distance = distance;
      this.speedLimit = speedLimit;
   }
}

A given route will be defined by an array of segments:

final Segment[] route = new Segment[] {
   new Segment(2.4, 50)
  ,new Segment(5, 100)
  ,new Segment(3.1, 50)
  ,new Segment(0.8, 30)
};

Implement a method duration(...) which allows for calculation the minimum expected time required with respect to speed limits along a given route.

/**
 * Minimal time required when consequently traveling with the minimum of
 * official speed limits and the driver's personal maximum speed. If a
 * leg does not have any speed limit the value of personalSpeedLimit will
 * be used for calculation instead.
 *
 * @param route The array of segments composing a route.
 *
 * @param personalSpeedLimit The drivers personal speed limit whether or
 *        not official limits apply. Must be greater than 0.
 *
 * @return The minimal duration in (rounded) minutes with respect to all
 *         speed limits. Must be a positive (non-zero) value.
*/
static public long duration(Segment[] route, int personalSpeedLimit) {
  return 0; // TODO
}

Write Junit tests to cover different situations.

Tip

You may want to start implementing a main() method example first to gain some experience:

public class Driver {
   /**
    * Main entry point.
    */
   static void main() {

      final Segment[] route = new Segment[] {
            new Segment(2.4, 50)
            ,new Segment(5, 100)
            ,new Segment(3.1, 50)
            ,new Segment(0.8, 30)
      };
      ...

      final long fullMinutes = ...;

      IO.println("Minimal duration:" + fullMinutes);
}

A:

exercise No. 145

Examinations and mark frequencies

Q:

Consider an examination resulting in the following list of marks:

Participant no. 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
Mark 2 1 3 3 5 4 1 2 2 4 3 2 3 3 1 5 3 4

You may represent this examination result by:

final int[] marks = {2,1,3,3,5,4,1,2,2,4,3,2,3,3,1,5,3,4};

Lecturers and participants may be interested in the distribution of marks i.e. their frequencies. Thus having marks in a range from 1 to 5 in the given example we'd like to create the following overview of marks:

Mark Frequency
1 3
2 4
3 6
4 3
5 2

Write a Java application turning an array of participants' marks into the above table of marks among with their respective frequencies. For the given example the intended terminal output reads:

Mark|frequency
————+—————————
   1|3
   2|4
   3|6
   4|3
   5|2

Your application shall work for other marking schemes (i.e. marks ranging from -2 to 10) as well. Define a suitable class like:

public class MarkFrequencies {

  public final int[] frequencyByMark;
  public final int lowestMarkValue;

  public MarkFrequencies(final int[] markValues) {
    ...
  }
}

The constructor assigning values to both lowestMarkValue and frequencyByMark and is not yet implemented. Upon completion you may use class MarkFrequencies for producing the previously detailed terminal output:

final MarkFrequencies markFrequencies =
    new MarkFrequencies(new int[]{2,1,3,3,5,4,1,2,2,4,3,2,3,3,1,5,3,4});

// Create overview of marks:
//
IO.println("Mark|frequency");
IO.println("————+—————————");

for (int i = 0; i < markFrequencies.frequencyByMark.length ; i++) {
  IO.println("   " + (markFrequencies.lowestMark + i) + "|" +
    markFrequencies.frequencyByMark[i]);
}

Provide appropriate unit tests beforehand.

Tip

  1. Get the minimum and maximum mark of all participants beforehand.

  2. Create the int[] frequencyByMark array. Since you already know both your mark list's minimum and maximum the frequencies array's size is thus determined. Shift each mark by the mark list's minimum and regard each mark as an index value. Example:

    • The list of marks is {-2, -1, 0, 1, 2, 3}.

    • The minimum mark is -2 and the maximum equals 3.

    • The list of marks shifted by -2 will start with 0:

    • {0, 1, 2, 3, 4, 5}

    • The array of mark frequencies thus contains 6 elements.

After implementing your method extend your application to allow for being called from the command line like:

marking> mvn package
  ....
marking> java -jar target/marking-0.9.jar 2 1 3 3 5 4 1 2 2 4 3 2 3 3 1 5 3 4

Mark|frequency
————+—————————
   1|3
   2|4
   3|6
   4|3
   5|2

This requires evaluating the args parameter from your main(String[] args) method.

Tip

  1. Converting a string like "5" into an int value of 5 may be achieved using:

    int value = Integer.parseInt("5")
  2. The maven-shade-plugin inside your project's pom.xml allows for creating executable jar archives. If your main(...) method is being defined in a class de.hdm_stuttgart.mi.marking.Marks . You may define this class to become the overall execution entry point by virtue of a corresponding pom.xml entry:

    ...
    <plugin>
      <groupId>org.apache.maven.plugins</groupId>
      <artifactId>maven-shade-plugin</artifactId>
      <version>3.1.0</version>
      <configuration>
        <transformers>
          <transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
            <manifestEntries>
              <Main-Class>de.hdm_stuttgart.mi.marking.Marks</Main-Class>
            </manifestEntries>
          </transformer>
        </transformers>
      </configuration>
      <executions>
        <execution>
          <phase>package</phase>
          <goals>
            <goal>shade</goal>
          </goals>
        </execution>
      </executions>
    </plugin>
    ...

    Executing mvn package will then create an executable jar archive as outlined above.

A:

The method int[] de.hdm_stuttgart.mi.marking.Marks.getFrequencies(int[] values) is being defined in a slightly more general way possibly being useful in similar situations as well. This way it becomes subject to unit testing:

public class AppTest {

  @Test
  public void testSingle() {
      Assertions.assertArrayEquals(
          new int[]{1},
          Marks.getFrequencies(new int[]{-3}));
  }

  @Test
  public void testMultiple() {
      Assertions.assertArrayEquals(
          new int[]{2, 1, 0, 0, 0, 2, 0, 3},
          Marks.getFrequencies(new int[]{-3, 4 , 2, -2, 4, -3, 2, 4}));
  }
}

exercise No. 146

External string exercises

Q:

Try solving as many examples as possible from the String-3 sections.

Figure 388. Array instances are special! Slide presentation
...println("        String: " + "".getClass().getTypeName());
...println("         int[]: " + new int[]{}.getClass().getTypeName());
...println("      double[]: " + new double[]{}.getClass().getTypeName());
...println("     boolean[]: " + new boolean[]{}.getClass().getTypeName());
...println("StringBuffer[]: " + new StringBuffer[]{}.getClass().getTypeName());
        String: java.lang.String
         int[]: int[]
      double[]: double[]
     boolean[]: boolean[]
      String[]: java.lang.String[]
StringBuffer[]: java.lang.StringBuffer[]

Figure 389. Array creation details Slide presentation

Figure 390. Array parameter passing Slide presentation
static void main() {
  final int [] lectures = new int[3]; // Three lectures
  fill(lectures, 25); // Default lecture having 25 participants
  IO.println("Second lecture has got " + lectures[1] +
          " participants");
}
/**
  * Initialize array with default value.
  *
  * @param values Array to be initialized.
  * @param common New value for all array elements.
  */
static void fill(final int[] values, final int common) {
  for (int i = 0; i < values.length; i++) {
    values[i] = common;
  }
}
Second lecture has got 25 participants

Figure 391. Parameter passing details Slide presentation

Figure 392. Array initializer: Value and reference types Slide presentation
// Value type
final boolean values[] = {true, true, false, true};

// Reference type
final String shapes[] = {"Triangle", "Circle"};