LogMessage free response answer 15

LogMessage free response problem from the 2016 AP Computer Science A Exam.

LogMessage is #2 from the from the 2016 AP Computer Science A Free Response problems.

https://secure-media.collegeboard.org/digitalServices/pdf/ap/ap16_frq_computer_science_a.pdf

Part (a) – LogMessage constructor

public LogMessage(String message)
{
  int colonIndex = message.indexOf(":");
  machineId = message.substring(0, colonIndex);
  description = message.substring(colonIndex + 1);
}

The constructor requires that a string be split into 2 parts. This is very similar to the AP CS Magpie Lab.

Part (b) – containsWord method

public boolean containsWord(String keyword)
{
  int keywordIndex = description.indexOf(keyword);
  
  while(keywordIndex != -1)
  {
    int beforeIndex = keywordIndex - 1;
    int afterIndex = keywordIndex + keyword.length();
    
    if((beforeIndex == -1 ||
        description.substring(beforeIndex, beforeIndex + 1).equals(" ")) &&
        (afterIndex == description.length() ||
        description.substring(afterIndex, afterIndex + 1).equals(" ")))
      return true;
    
    keywordIndex = description.indexOf(keyword, keywordIndex + 1);
  }
  
  return false;
}

The good folks at Skylit have a clever solution to part (b).

This problem is a simpler version of a method in the AP CS Magpie Lab that identifies words that are not contained within other words. The method in the Magpie Lab checked for any non-letter characters surrounding the desired word, while this method checks only for spaces.

This solution uses the 2 parameter indexOf method, as does the AP CS Magpie Lab. The alternate solution below sticks to the single parameter indexOf method from the Quick Reference.

Part (b) – containsWord method – alternate solution

public boolean containsWord(String keyword)
{
  for(int i = 0; i < description.length(); i++)
  {
    int keywordIndex = description.substring(i).indexOf(keyword);

    if(keywordIndex != -1)
    {
      int beforeIndex = keywordIndex - 1 + i;
      int afterIndex = keywordIndex + keyword.length() + i;

      if((beforeIndex == -1 ||
          description.substring(beforeIndex, beforeIndex + 1).equals(" ")) &&
          (afterIndex == description.length() ||
          description.substring(afterIndex, afterIndex + 1).equals(" ")))
        return true;
    }
  }

  return false;
}

This solution uses only the indexOf method with a single parameter from the Quick Reference.

Part (c) – removeMessages method

public List<LogMessage> removeMessages(String keyword)
{
  ArrayList<LogMessage> removedMessages = new ArrayList<LogMessage>();
  
  for(int i = 0; i < messageList.size(); i++)
  {
    if(messageList.get(i).containsWord(keyword))
    {
      removedMessages.add(messageList.remove(i));
      i--;
    }
  }
  
  return removedMessages;
}

This is a standard traversal through a list with removal. I usually prefer to loop through a list backwards to account for the shift; however, I decremented i here instead so that I could add each removed element to the end of the new list. (Alternatively, it is possible to add each removed element to the beginning of the new list.)

15 thoughts on “LogMessage free response answer

  1. Reply Charan Bachu May 5,2016 7:46 pm

    For containsWord, could you not have used String.split method and split at ” “? This way you can just search the array for the key word. If it has the keyword then you return true. Otherwise false.

  2. Reply missevadee May 5,2016 9:20 pm

    How about this alternate solution? Did I miss anything?

    public boolean containsWord(String keyword)
    {
       int i = description.indexOf(keyword);
       if (i < 0)  return false;
    
       String d = description;
       String k = keyword;
       int dL = description.length();
       int kL = keyword.length();
    
       if (i == 0 && dL == kL)  return true;
       
       if (d.indexOf(k + " ") == 0) return true;
    
       if (d.substring(dL - kL - 1).equals(" " + k)) return true;
       
       if (d.indexOf(" " + k + " ") > 0)  return true;
       
       return false;
    }
    
    • Reply Brandon Horn May 5,2016 9:32 pm

      Looks great.

      Sorry for my original comment indicating it didn’t work. I didn’t catch the clever use of padding.

  3. Reply missevadee May 5,2016 10:01 pm

    I still don’t see how my code won’t work with the concatenated spaces, but have just been given a much more elegant (and efficient) solution from a colleague:

    public boolean containsWord(String keyword)
    {
      return (" " + description + " ").indexOf(" " + keyword + " ") >= 0;
    }
    
    • Reply Brandon Horn May 6,2016 7:56 am

      Now this I like!

      • Reply Charan Bachu May 8,2016 7:25 pm

        But does this work if the keyword is at the very end or beginning of the message?

        • Reply Brandon Horn May 11,2016 6:05 pm

          Yes. If the keyword is at the beginning of the message it will have a space both before and after (since the description has been padded with spaces. The same applies at the end of the message.

  4. Reply Billy May 6,2016 12:10 pm

    What if I included the : in machine ID? How many points would I lose?

    • Reply Brandon Horn May 6,2016 4:28 pm

      The scoring guides haven’t been released yet. My guess would be 0.5 to 1 point.

      • Reply James May 11,2016 12:23 pm

        My understanding is that half points are no longer an option. I believe I heard it at an AP 2-day workshop, but it has been a year or two.

        • Reply Brandon Horn May 11,2016 6:03 pm

          Could be. I have no idea. I’ll be interested to see the scoring guide for this problem.

  5. Reply Billy May 7,2016 2:04 pm

    Do you feel this is going to have a big curve? I feel like the FRQs were so much harder than last year.

    • Reply Brandon Horn May 11,2016 6:09 pm

      I don’t know how the cutoff scores are determined. My guess would be that they are based on both the multiple choice and the free response.

Leave a Reply