Review Ticket
FRQ 1: Arrays and Array Lists
The original FRQ wanted us to loop through an array and calculate values and analytical data. In my PBL project, I still used the ideas relating to the arrays and array lists, however, it wasn't the same. As seen in the following code chunk, I iterate through a list to find specific values that are important to our algorithm and backend processing. In addition, while not quite a 2D array, the usage of a hashmap can also be seen, showing the methods of storing data under different entry dates with each stock ticker and its number of shares/price predicted.
// Extract Attributes from JSON
Map<String, Object> attributeMap = new HashMap<>();
String[] stocks = {"AAPL", "AMZN", "COST", "GOOGL", "LMT", "META", "MSFT", "NOC", "TSLA", "UNH", "WMT"};
for (Map.Entry<String,Object> entry : stat_map.entrySet()) {
// Add all attributes other than "date" and "id" to the "attribute_map"
if (!entry.getKey().equals("date") && !entry.getKey().equals("id")) {
// Handle each stock case
for (String stock : stocks) {
if (entry.getKey().equals(stock)) {
// String shares=String.valueOf(entry.getValue());
attributeMap.put(entry.getKey(), entry.getValue()); // Add stock attribute
break;
}
}
if (entry.getKey().equals("Balance")) {
// String shares=String.valueOf(entry.getValue());
attributeMap.put(entry.getKey(), entry.getValue()); // Add stock attribute
break;
}
}
}
FRQ 2: Classes
Almost all of my work on our PBL project was done with classes, especially the stock info classes. As seen in the following code segment, there is the usage of a Stock public class, along with multiple methods, such as the Stock setter method, as well as the getTotalCost and getTotalShares methods which both rely on the manipulation and analysis of data in order to return their values. You can also see an init function for the initialization of testing/initial prediction data for the database.
@Data
@AllArgsConstructor
@NoArgsConstructor
@Entity
@Convert(attributeName ="stock", converter = JsonType.class)
public class Stock {
// automatic unique identifier for Person record
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
// name, share cost, roles are key attributes to login and authentication
@NotEmpty
@Column(unique=true)
private String name;
@DateTimeFormat(pattern = "yyyy-MM-dd") //should probably change to time to be more accurate
private Date time;
@NotEmpty
private Double cost;
@NotEmpty
private Integer shares;
// Are we selling or buying the stock?
// @NotEmpty
// private String operation;
@JdbcTypeCode(SqlTypes.JSON)
@Column(columnDefinition = "jsonb")
private Map<String,Map<String, Object>> stats = new HashMap<>();
// Essentially, we record who buys the stock (id), what stock they bought (name), cost of the share (cost), amount of the shares (shares), time of the transaction (time), and whether it was bought or sold (operation)
public Stock(String name, Double cost, Integer shares, String operation, Date time) {
this.name = name;
this.cost = cost;
this.shares = shares;
this.time = time;
// this.operation = operation;
}
// A custom getter to return cost of a transaction
public double getTotalCost() {
if (this.cost != null && this.shares != null) {
return cost*(float)shares;
}
return -1;
}
// A custom getter to update total number of shares owned
public double getTotalShares() {
if (this.name != null && this.shares != null) {
// this is placeholder for now, we should get existing shares and subtract
return cost*(float)shares;
}
return -1;
}
// Initialize static test data
public static Stock[] init() {
// basics of class construction
Stock s1 = new Stock();
s1.setName("AAPL");
s1.setCost(188.91);
s1.setShares(15);
Date d;
try {
d = new SimpleDateFormat("MM-dd-yyyy").parse("02-06-2024");
s1.setTime(d);
} catch (ParseException e) {
System.out.println("Date parse exception ======================");
e.printStackTrace();
}
// p1.setOperation("buy"); <-- we can set this on frontend and adjust shares to + or -. If shares is 0 we assume update
// Array definition and data initialization
Stock stocks[] = {s1};
return(stocks);
}
public static void main(String[] args) {
// obtain Person from initializer
Stock stocks[] = init();
// iterate using "enhanced for loop"
for( Stock stock : stocks) {
System.out.println(stock); // print object
}
}
}
FRQ 3: 2D Arrays/Sparse Arrays
Again, there weren't too many instances of using a 2D array in my side of the project, as when working with a database, dictionaries and hashmaps will do the trick much more efficiently. With that being said, refer to the following code segment, where I am creating a new hashmap called attributeMap containing the date of the entry as well as the value of each stock attribute that the user decides to purchase. This could be easily adapted into a 2D array, however, as seen in the code segment comments, it would be much MUCH more complicated.
// Extract Attributes from JSON
/* 2D array mockup for issue:
* [[id, appl, amzn, cost, google, lmt, meta, msft, noc, tsla, unh, wmt]]
* example:
* [[1, 0, 1, 23, 0, 0, 0, 1, 2, 3, 4, 5], [2, 0, 1, 23, 0, 0, 0, 1, 2, 3, 4, 5], [3, 0, 1, 23, 0, 0, 0, 1, 2, 3, 4, 5]]
* Now when getting the info, its MUCH harder to tell what I'm trying to get, as well as having to mess with the actual accessing of data being a nightmare, as not always will the UIDs be in perfect numerical order like this (e.g. if a user deletes their account)
* /
Map<String, Object> attributeMap = new HashMap<>();
String[] stocks = {"AAPL", "AMZN", "COST", "GOOGL", "LMT", "META", "MSFT", "NOC", "TSLA", "UNH", "WMT"};
for (Map.Entry<String,Object> entry : stat_map.entrySet()) {
// Add all attributes other than "date" and "id" to the "attribute_map"
if (!entry.getKey().equals("date") && !entry.getKey().equals("id")) {
// Handle each stock case
for (String stock : stocks) {
if (entry.getKey().equals(stock)) {
// String shares=String.valueOf(entry.getValue());
attributeMap.put(entry.getKey(), entry.getValue()); // Add stock attribute
break;
}
}
if (entry.getKey().equals("Balance")) {
// String shares=String.valueOf(entry.getValue());
attributeMap.put(entry.getKey(), entry.getValue()); // Add stock attribute
break;
}
}
}
FRQ 4: Interfaces
The last FRQ was about Java interfaces, and this was used quite a bit in our person and stock API. As I worked mostly on the stock API, the code segments will focus on that. As can be seen in the following code segment, this is an interface that extends the JPARepository class, defining multiple extremely useful functions that can be used when implementing the StockJpaRepository class, such as finding a stock by its name (findByName), ordering the stocks (findAllByOrderByNameAsc();), as well as a specifically implemented method helping us to find specific stocks by its registered admin email and password (findByEmailAndPassword).
public interface StockJpaRepository extends JpaRepository<Stock, Long> {
Stock findByName(String name);
List<Stock> findAllByOrderByNameAsc();
// JPA query, findBy does JPA magic with "Name", "Containing", "Or", "Email", "IgnoreCase"
List<Stock> findByNameContainingIgnoreCaseOrEmailContainingIgnoreCase(String name, String email);
/* Custom JPA query articles, there are articles that show custom SQL as well
https://springframework.guru/spring-data-jpa-query/
https://docs.spring.io/spring-data/jpa/docs/current/reference/html/#jpa.query-methods
*/
Stock findByEmailAndPassword(String email, String password);
// Custom JPA query
@Query(
value = "SELECT * FROM Person p WHERE p.name LIKE ?1 or p.email LIKE ?1",
nativeQuery = true)
List<Stock> findByLikeTermNative(String term);
/*
https://www.baeldung.com/spring-data-jpa-query
*/
}
Overall reflection
-
FRQ 1: This was probably the 2nd easiest FRQ on the test, as all it had to do was figure out how to add up values in an array. After solving part A, I could easily extrapolate it out to the remainder of the parts for an easy solution. The only part that required a bit more thinking was the last, section C. Taking a look at my code segments, you can see how I was able to use the knowledge of iteration through the lists in order to apply it over to the 2015 FRQ!
-
FRQ 2: This was also a pretty easy FRQ, as all it required me to do was implement a rudimentary version of the game "Wordle" which I have created before. The only challenge with this one was the sequence in which the if statements were ordered in. Had I not been careful and arbitrarily ordered the if statements, some conditions would have been triggered before others, and thus, mess up the output of the code. Additionally, the usage of classes in my PBL helped me get a solid understanding of the underlying code structure, saving me valuable time, as I don't have to think too hard about the pre-existing code and can jump straight into the ideation and implementation.
-
FRQ 3: This was the most difficult FRQ, yet it still wasn't too confusing to do. The FRQ just required a little critical thinking on how exactly to implement the deletion of a column while still preserving the value, and the solution to this was just to move the value over to an adjacent column. The challenge with this FRQ was figuring out how exactly to present the data to the reader of my blog. (how to implement extra methods to display data) While I didn't directly work with 2D arrays in my PBL, the knowledge of what would have happened in the case of using a 2D array helped me, as I was able to develop a clear mental image of 2D arrays and how to process it.
-
FRQ 4: This was the easiest FRQ by far, as it was just a checker to see if a number was between two other numbers. Add on the fact that I worked closely with interfaces through our PBL project, this FRQ was a breeze, and I had no trouble with it whatsoever!
This whole activity with the FRQs and reflection really helped me to see how exactly I am preparing for the AP exam! Its really reassuring knowing that for the FRQs I have been practicing them through my PBL, and I can see the results when doing the 2015 practice FRQ!