How to start on this Priority Queue homework? - java

Could someone give me hints on how to solve this problem?
A store announces a sale campaign whereby any customer who buys two items gets 50% off on the cheaper one. If the customer buys more than two items, he/she must group them into pairs of two to indicate the items that the oer should apply to.
Suppose you want to buy n items in total. Write a method that will give you the best pairing of the items (the one with the minimum price). The method's signature is:
public static LinkedList<ItemPair> minPairing(LinkedList<Item> items).
If you leave it up to the store owner, he/she will try to pair the items in order to obtain the maximum price. Write a method that will help the store owner achieve this. The method's signature is:
public static LinkedList<ItemPair> maxPairing(LinkedList<Item> items).
How much will you gain if you use your method (instead of the shop owner's method) for the following list of item prices: 60 $, 100 $, 400 $, 600 $, 200 $, 80 $.
Using the following classes:
public class Item {
private int id;
private double price;
public Item (int id, double price ) {
this.id = id;
this. price = price;
}
int getId () {
return id;
}
double getPrice () {
return price;
}
}
and the class :
public class ItemPair {
public Item first;
public Item second;
public ItemPair (Item first, Item second ) {
this. first = first;
this. second = second;
}
}

Edited to add PriorityQueue as requested.
For minPairing() copy the items into a new PriorityQueue<Item> with a Comparator<Item> which compares the items prices. Then always pair (ItemPair) the top ones from the queue using .poll(). Repeat until list ist empty.
To create the PriorityQueue try this:
PriorityQueue<Item> pq = new PriorityQueue<Item>(items.size(), new Comparator<Item>() {
public int compare(Item i1, Item i2) {
return Float.compare(i1.getPrice(), i2.getPrice());
});
for (Item item : items) {
pq.add(item);
}
For maxPairing() - in my opinion - a PriorityQueue doesn't make much sense, as you need to pair the most expensive one with the cheapest one. I would just go with a sorted List<Item> here (see Collections.sort(List, Comparator)). Pick the first and the last item from the list and create an ItemPair. Then remove both from the list. Repeat until list ist empty.
compare the sum of the prices of the ItemPairs provided by those two methods.
You may need to implement a getPrice() method to ItemPair:
double getPrice () {
// assumes that second is cheaper one:
return first.getPrice() + (second.getPrice() / 2);
}

Related

Changing complexity from O(n) to o(logn)

We have a linkedlist called ratings that contains 3 integers
userId, ItemId and value of the actual rating (example from 0 to 10)
this method actually returns rating of User i and item j that the programs reads it from a File and returns -1 if there is no rating
the method that is BigOh(n) :
public int getRating(int i, int j){
ratings.findFirst();
while(!ratings.empty()){
if(ratings.retrieve().getUserId() == i && ratings.retrieve().getItemId() == j)
return ratings.retrieve().getValue();
else
ratings.findNext();
}
return -1;
}
How can I do this in BigOh(logn)?
Or is there anyway I can solve it using Binary Search tree?
The short answer is: use a different data structure. Linked lists aren't capable of doing searches in anything other than linear time, since each element is linked together without any real semblance or order (and even if the list were sorted, you'd still have to do some kind of timed traversal).
One data structure that you could use would be a Table from Guava. With this data structure, you'd have to do more work to add an element in...
Table<Integer, Integer, Rating> ratings = HashBasedTable.create();
ratings.put(rating.getUserId(), rating.getItemId(), rating);
...but you can retrieve very quickly - in roughly O(1) time since HashBasedTable is backed by LinkedHashSet<Integer, LinkedHashSet<Integer, Rating>>.
ratings.get(i, j);
You can use hashing to achieve your task in O(1). Please read this article to gain a deeper understanding about hashing.
Since you are using Java, you can use HashMap to accomplish your task. Note that, worst case time complexity for hashing technique is O(log n) but on average it is O(1). If you are more interested to know about hash tables and amortized analysis, please go through this article.
Code Example: You can create a Class with the required attributes and implement equals and hashCode method as follows. [read Java collections - hashCode() and equals()]
class Rating {
public int user_id; // id of the user who rated
public int item_id; // id of the item being rated
public Rating(int user_id, int item_id) {
this.user_id = user_id;
this.item_id = item_id;
}
#Override
public boolean equals(Object o) {
if (o == this) {
return true;
}
if (!(o instanceof Rating)) {
return false;
}
Rating ratingObj = (Rating) o;
return ratingObj.user_id == user_id
&& ratingObj.item_id == item_id;
}
#Override
public int hashCode() {
int result = 17;
result = 31 * result + user_id;
result = 31 * result + item_id;
return result;
}
}
Then store values in HashMap as follows:
public static void main(String[] args) {
HashMap<Rating, Integer> ratingMap = new HashMap<>();
Rating rt = new Rating(1, 5); // user id = 1, item id = 5
ratingMap.put(rt, 3);
rt = new Rating(1, 2); // user id = 1, item id = 2
ratingMap.put(rt, 4);
rt = new Rating(1, 3); // user id = 1, item id = 3
ratingMap.put(rt, 5);
// now search in HashMap
System.out.println(ratingMap.get(new Rating(1, 3))); // prints 5
}
As presented, this could hardly be done in O(log n). You're looking through elements until you find the one you need. In the worst case, you won't find the element you want until the end of the loop, thus making it O(n).
Of course, if ratings were a dictionary you'd retrieve the value in almost O(1): user ids as keys and for example a list of ratings as value. Insertion would be a bit slower but not much.

How to calculate the rank of a player from a list

Say I have following simple data structure.
public class Player {
private Long id;
private String name;
private Integer scores;
//getter setter
}
So far so good. Now question is , how do I get what's a players rank?
I have another data structure for ranking, that is-
public class Ranking {
private Integer score;
private Integer rank;
//getter/setter
}
So I have a list of player and i want to compute a list of ranking and I would like to use java8 stream api.
I have a service named PlayerService as following
public class PlayerService {
#Autowired
private PlayerRepository playerRepository;
public List<Ranking> findAllRanking(Long limit) {
List<Player> players = playerRepository.findAll();
// calculation
return null;
}
The calculation is simple, whoever has most score has most ranking.
If I have 5,7,8,9,3 scores then ranking would be
rank score
1 9
2 8
3 7
4 5
5 3
Any help would be appreciated.
Try this:
List<Player> players = new ArrayList<Player>() {{
add(new Player(1L, "a", 5));
add(new Player(2L, "b", 7));
add(new Player(3L, "c", 8));
add(new Player(4L, "d", 9));
add(new Player(5L, "e", 3));
add(new Player(6L, "f", 8));
}};
int[] score = {Integer.MIN_VALUE};
int[] no = {0};
int[] rank = {0};
List<Ranking> ranking = players.stream()
.sorted((a, b) -> b.getScores() - a.getScores())
.map(p -> {
++no[0];
if (score[0] != p.getScores()) rank[0] = no[0];
return new Ranking(rank[0], score[0] = p.getScores());
})
// .distinct() // if you want to remove duplicate rankings.
.collect(Collectors.toList());
System.out.println(ranking);
// result:
// rank=1, score=9
// rank=2, score=8
// rank=2, score=8
// rank=4, score=7
// rank=5, score=5
// rank=6, score=3
The variables score, no and rank are free variables in the lambda function in .map(). So they must not be reassigned. If their types are int instead of int[], you cannot compile the code.
The problem with the accepted answer is that once you turn the stream in parallel (players.parallelStream()), you'll get unexpected results, because of race conditions when you read/update the value from the singletons arrays.
Maybe you could decompose your task into multiple steps. First sort the list of scores into reverse order, and then generate a stream of indices. From there you map each index to its corresponding rank.
You need to test multiple conditions into the mapToObj statement if you need to have the same rank for a same score. It makes the code not very pretty but you can always extract this in a helper method.
List<Integer> scores = players.stream().map(Player::getScores).sorted(reverseOrder()).collect(toList());
List<Ranking> rankings =
IntStream.range(0, scores.size())
.mapToObj(i -> i == 0 ? new Ranking(1, scores.get(i)) :
scores.get(i - 1).equals(scores.get(i)) ? new Ranking(i, scores.get(i)) :
new Ranking(i + 1, scores.get(i)))
.collect(toList());
That said, if you don't plan to parallelize this step, I would go with the good old for-loop.
If you don't need to have the same rank for the same score, you can check this thread Zipping streams using JDK8 with lambda (java.util.stream.Streams.zip), for example with proton-pack:
List<Ranking> rankings = StreamUtils.zip(IntStream.rangeClosed(1, players.size()).boxed(),
players.stream().map(Player::getScores).sorted(reverseOrder()),
Ranking::new)
.collect(toList());
You will get a better solution, if you rethink your prerequisites first. As a side note, I don’t understand, why you are using Integer throughout your code. If you really consider null a possible value for rank or scores, the solution will become much more complicated. Since I doubt that this is what you want, I recommend using int instead.
The biggest obstacle is your requirement of producing this rather superfluous Ranking instances. All you need, are the scores as once sorted, their rank is implied by their positions:
List<Integer> rankAndScore = players.stream().map(Player::getScores)
.sorted(Comparator.reverseOrder()).collect(toList());
this resulting list contains the scores in descending order and the rank is implied by the position, the first item has the first rank, the second item the second, and so on. There is no need to explicitly store the rank numbers. The only thing to care is that the collection indices start with zero whereas the ranks start with one.
One way to print the values as in your question is:
System.out.println("rank\tscore");
IntStream.range(0, rankAndScore.size())
.forEachOrdered(r->System.out.println(r+1+"\t"+rankAndScore.get(r)));
Alternatively, you could simply use an int[] array to represent rank and score:
int[] rankAndScore = players.stream().mapToInt(Player::getScores).sorted().toArray();
System.out.println("rank\tscore");
IntStream.rangeClosed(1, rankAndScore.length)
.forEachOrdered(r->System.out.println(r+"\t"+rankAndScore[rankAndScore.length-r]));
The IntStream doesn’t support sorting in descending order but as shown, it can be simply fixed by sorting to ascending order and adapting the processing of the array.
I believe you want the Player to have as an attribute, a Ranking, right? Why not add a member variable (or instance variable) in the player's class. I believe we call this "aggregation" or "Object composition" in object oriented programming. https://en.wikipedia.org/wiki/Object_composition
Consider this...
public class Player {
private Long id;
private String name;
private Integer scores;
private Ranking rank;
...
//You can add a constructor that include the Ranking, you can also add setter and getters to set the Ranking object for this player.
public int getRank()
{
return rank.getRank(); //assuming class Ranking has getRank() method
}
public void setRank(int rank)
{
rank.setRank(rank); //assuming class Ranking has setRank()
}
}
Why not sort the payers according to their score?
so.. something along those lines:
public class PlayerService {
#Autowired
private PlayerRepository playerRepository;
public List<Ranking> findAllRanking(Long limit) {
List<Player> players = playerRepository.findAll();
// --- sorting players according to their scores
Collections.sort(players, new Comparator<Player>(){
#Override
public int compare(Players thiz, Player that){
return new Integer(thiz.scores).compareTo(that.scores);
});
List<Ranking> rankingList = new ArrayList<>();
int i = 0;
for(Player p : players){
rankingList.add(new Ranking(p.score, ++i));
}
return rankingList;
}
I leave that as an exercise to you to determine if that produces your wanted order or the exact reverse.

Remove an object from an ArrayList given only one attribute

I have an ArrayList of Items and I want to be able remove one Item from the list by entering only one Item attribute, for example its number (int ItemNumber). I also wanna do the same when I check Item quantities.
These are my equals() & contains() methods, do I need to make any changes here?
public boolean contains(T anEntry) {
boolean found = false;
for (int index = 0; !found && (index < numberOfEntries); index++) {
if (anEntry.equals(list[index]))
found = true;
}//end for
return found;
} // end contains
public boolean equals(Object object){
Item item = (Item) object;
if (itemNo == item.itemNo)
return true;
return false;
}
If you change the class Item equals() and compareTo() methods, so that they check only one object field, such as a quantity, it could result in strange behavior in other parts of your application. For example, two items with different itemNo, itemName, and itemPrice, but with the same quantities could be considered equal. Besides, you wouldn't be able to change the comparison attribute without changing the equals() code every time.
Also, creating a custom contains() method makes no sense, since it belongs to the ArrayList class, and not to Item.
If you can use Java 8, a clean way to do it is to use the new Collection's removeIf method:
Suppose you have an Item class with the num and name properties:
class Item {
final int num;
final String name;
Item(int num, String name) {
this.num = num;
this.name = name;
}
}
Given a List<Item> called items and an int variable called number, representing the number of the item you want to remove, you could simply do:
items.removeIf(item -> item.num == number);
If you are unable to use Java 8, you can achieve this by using custom comparators, binary search, and dummy objects.
You can create a custom comparator for each attribute you need to look for. The comparator for num would look like this:
class ItemNumComparator implements Comparator<Item> {
#Override
public int compare(Item a, Item b) {
return (a.num < b.num) ? -1 : ((a.num == b.num) ? 0 : 1);
}
}
Then you can use the comparator to sort and search for the desired elements in your list:
public static void main(String[] args) {
List<Item> items = new ArrayList<>();
items.add(new Item(2, "ball"));
items.add(new Item(5, "cow"));
items.add(new Item(3, "gum"));
Comparator<Item> itemNumComparator = new ItemNumComparator();
Collections.sort(items, itemNumComparator);
// Pass a dummy object containing only the relevant attribute to be searched
int index = Collections.binarySearch(items, new Item(5, ""), itemNumComparator);
Item removedItem = null;
// binarySearch will return -1 if it does not find the element.
if (index > -1) {
// This will remove the element, Item(5, "cow") in this case, from the list
removedItem = items.remove(index);
}
System.out.println(removedItem);
}
To search for another field like name, for example, you would need to create a name comparator and use it to sort and run the binary search on your list.
Note this solution has some drawbacks though. Unless you are completely sure that the list didn't change since the last sort, you must re-sort it before running the binarySearch() method. Otherwise, it may not be able to find the correct element. Sorting complexity is O(nlogn), so running it multiple times can get quite expensive depending on the size of your list.
Do you want to remove an object at a specific index? I'm not entirely sure what you mean by 'number field'. If so, jump to method: remove(int):
http://docs.oracle.com/javase/7/docs/api/java/util/ArrayList.html#remove%28int%29
EDIT: If you want to find/adjust a field of an object in the Array list, you can do this (piece of my own code):
public boolean studentHasISBN(ArrayList<Student> st, String s){
for(Student j : st) {
if(s.equals(j.getRentedBookISBN()))
return true;
}
return false;
}
All you have to do is iterate through the list, and search through the field that you want to find. Then use the remove(int) method.
simply use the remove function of ArrayLists in Java:
theNameOfYourArrayList.remove(ItemNumber);
to remove the element which has the index (int ItemNumber)
to check if the element with item number (int ItemNumber) exists in your ArrayList (hypothetically called theNameOfYourArrayList):
theNameOfYourArrayList.get(ItemNumber);
I'm going to assume that by 'number field' you mean that you invoked ArrayList with the Integer data type. I have a few different solutions to your problem:
ArrayLists, assuming that the ArrayList is ArrayList<Integer> numList = new ArrayList<Integer>(); you can simply write a method that will search 'numList' and delete the index that the number is. The problem is, contains and find in ArrayLists can be slow.
public void deleteNumField(int field) {
// this will stop any error if field isn't actually in numList
// and it will remove the first index of field in the ArrayList
if(numList.contains(field)) numList.remove(numList.find(field));
}
HashSets, HashSets are a handy data type that is like an ArrayList, except, its data is its 'index' (sortof). I won't go in depth about how they work, but I will say that searching in them is considered O(1). This will make your deletion really easy, and fast. Note: the HashSet assumes there are no duplicate numbers, if there are use a HashMap.
HashSet<Integer> numList = new HashSet<Integer>();
public void deleteNumField(int field) {
// this will stop errors from attempting to remove a
// non-existant element, and remove it if it exists.
if(numList.contains(field)) numList.remove(field);
}
For more information on HashMaps, HashSets and ArrayLists, see:
http://docs.oracle.com/javase/8/docs/api/

A TreeSet or TreeMap that allow duplicates

I need a Collection that sorts the element, but does not removes the duplicates.
I have gone for a TreeSet, since TreeSet actually adds the values to a backed TreeMap:
public boolean add(E e) {
return m.put(e, PRESENT)==null;
}
And the TreeMap removes the duplicates using the Comparators compare logic
I have written a Comparator that returns 1 instead of 0 in case of equal elements. Hence in the case of equal elements the TreeSet with this Comparator will not overwrite the duplicate and will just sort it.
I have tested it for simple String objects, but I need a Set of Custom objects.
public static void main(String[] args)
{
List<String> strList = Arrays.asList( new String[]{"d","b","c","z","s","b","d","a"} );
Set<String> strSet = new TreeSet<String>(new StringComparator());
strSet.addAll(strList);
System.out.println(strSet);
}
class StringComparator implements Comparator<String>
{
#Override
public int compare(String s1, String s2)
{
if(s1.compareTo(s2) == 0){
return 1;
}
else{
return s1.compareTo(s2);
}
}
}
Is this approach fine or is there a better way to achieve this?
EDIT
Actually I am having a ArrayList of the following class:
class Fund
{
String fundCode;
BigDecimal fundValue;
.....
public boolean equals(Object obj) {
// uses fundCode for equality
}
}
I need all the fundCode with highest fundValue
You can use a PriorityQueue.
PriorityQueue<Integer> pQueue = new PriorityQueue<Integer>();
PriorityQueue(): Creates a PriorityQueue with the default initial capacity (11) that orders its elements according to their natural ordering.
This is a link to doc: https://docs.oracle.com/javase/8/docs/api/java/util/PriorityQueue.html
I need all the fundCode with highest fundValue
If that's the only reason why you want to sort I would recommend not to sort at all. Sorting comes mostly with a complexity of O(n log(n)). Finding the maximum has only a complexity of O(n) and is implemented in a simple iteration over your list:
List<Fund> maxFunds = new ArrayList<Fund>();
int max = 0;
for (Fund fund : funds) {
if (fund.getFundValue() > max) {
maxFunds.clear();
max = fund.getFundValue();
}
if (fund.getFundValue() == max) {
maxFunds.add(fund);
}
}
You can avoid that code by using a third level library like Guava. See: How to get max() element from List in Guava
you can sort a List using Collections.sort.
given your Fund:
List<Fund> sortMe = new ArrayList(...);
Collections.sort(sortMe, new Comparator<Fund>() {
#Override
public int compare(Fund left, Fund right) {
return left.fundValue.compareTo(right.fundValue);
}
});
// sortMe is now sorted
In case of TreeSet either Comparator or Comparable is used to compare and store objects . Equals are not called and that is why it does not recognize the duplicate one
Instead of the TreeSet we can use List and implement the Comparable interface.
public class Fund implements Comparable<Fund> {
String fundCode;
int fundValue;
public Fund(String fundCode, int fundValue) {
super();
this.fundCode = fundCode;
this.fundValue = fundValue;
}
public String getFundCode() {
return fundCode;
}
public void setFundCode(String fundCode) {
this.fundCode = fundCode;
}
public int getFundValue() {
return fundValue;
}
public void setFundValue(int fundValue) {
this.fundValue = fundValue;
}
public int compareTo(Fund compareFund) {
int compare = ((Fund) compareFund).getFundValue();
return compare - this.fundValue;
}
public static void main(String args[]){
List<Fund> funds = new ArrayList<Fund>();
Fund fund1 = new Fund("a",100);
Fund fund2 = new Fund("b",20);
Fund fund3 = new Fund("c",70);
Fund fund4 = new Fund("a",100);
funds.add(fund1);
funds.add(fund2);
funds.add(fund3);
funds.add(fund4);
Collections.sort(funds);
for(Fund fund : funds){
System.out.println("Fund code: " + fund.getFundCode() + " Fund value : " + fund.getFundValue());
}
}
}
Add the elements to the arraylist and then sort the elements using utility Collections.sort,. then implement comparable and write your own compareTo method according to your key.
wont remove duplicates as well, can be sorted also:
List<Integer> list = new ArrayList<>();
Collections.sort(list,new Comparator<Integer>()
{
#Override
public int compare(Objectleft, Object right) {
**your logic**
return '';
}
}
)
;
I found a way to get TreeSet to store duplicate keys.
The problem originated when I wrote some code in python using SortedContainers. I have a spatial index of objects where I want to find all objects between a start/end longitude.
The longitudes could be duplicates but I still need the ability to efficiently add/remove specific objects from the index. Unfortunately I could not find the Java equivalent of the Python SortedKeyList that separates the sort key from the type being stored.
To illustrate this consider that we have a large list of retail purchases and we want to get all purchases where the cost is in a specific range.
// We are using TreeSet as a SortedList
TreeSet _index = new TreeSet<PriceBase>()
// populate the index with the purchases.
// Note that 2 of these have the same cost
_index.add(new Purchase("candy", 1.03));
Purchase _bananas = new Purchase("bananas", 1.45);
_index.add(new Purchase(_bananas);
_index.add(new Purchase("celery", 1.45));
_index.add(new Purchase("chicken", 4.99));
// Range scan. This iterator should return "candy", "bananas", "celery"
NavigableSet<PriceBase> _iterator = _index.subset(
new PriceKey(0.99), new PriceKey(3.99));
// we can also remove specific items from the list and
// it finds the specific object even through the sort
// key is the same
_index.remove(_bananas);
There are 3 classes created for the list
PriceBase: Base class that returns the sort key (the price).
Purchase: subclass that contains transaction data.
PriceKey: subclass used for the range search.
When I initially implemented this with TreeSet it worked except in the case where the prices are the same. The trick is to define the compareTo() so that it is polymorphic:
If we are comparing Purchase to PriceKey then only compare the price.
If we are comparing Purchase to Purchase then compare the price and the name if the prices are the same.
For example here are the compareTo() functions for the PriceBase and Purchase classes.
// in PriceBase
#Override
public int compareTo(PriceBase _other) {
return Double.compare(this.getPrice(), _other.getPrice());
}
// in Purchase
#Override
public int compareTo(PriceBase _other) {
// compare by price
int _compare = super.compareTo(_other);
if(_compare != 0) {
// prices are not equal
return _compare;
}
if(_other instanceof Purchase == false) {
throw new RuntimeException("Right compare must be a Purchase");
}
// compare by item name
Purchase _otherPurchase = (Purchase)_other;
return this.getName().compareTo(_otherChild.getName());
}
This trick allows the TreeSet to sort the purchases by price but still do a real comparison when one needs to be uniquely identified.
In summary I needed an object index to support a range scan where the key is a continuous value like double and add/remove is efficient.
I understand there are many other ways to solve this problem but I wanted to avoid writing my own tree class. My solution seems like a hack and I am surprised that I can't find anything else. if you know of a better way then please comment.

Add element to arraylist and test if the number already exist

I have a method which add element to an arraylist
My task is to Modify the addProduct method so that a new product
cannot be added to the product list with the same ID
as an existing one.
Since both number and string are in the same word "item" and stored on the same index, I don't know how I can just get the number. I need the number to test to see if the number already exist
Any suggestion on how I should do this?
The way I add to the arraylist is like this below:
(new Product(132, "Clock Radio"))
public void addProduct(Product item)
{
stock.add(item);
}
I would greatly recommend you to go for Set inside the addProduct() method.
From the Javadocs,
SET
A collection that contains no duplicate elements. More formally, sets
contain no pair of elements e1 and e2 such that e1.equals(e2), and at
most one null element.
Implement like this,
public static boolean checkDuplicate(ArrayList list) {
HashSet set = new HashSet();
for (int i = 0; i < list.size(); i++) {
boolean val = set.add(list.get(i));
if (val == false) {
return val;
}
}
return true;
}
public void addProduct(Product item){
for (Product p: stock)
if (p.getId() == item.getId())
return;
stock.add(item);
}
I would use a java.util.Set. You would need to implement the equals() and hashcode() methods of the Product class based on the two fields passed into the constructor.
Try using a HashMap with the ID as the Key and the Item as the Value. In an HashMap you cant duplicate Items with the same Key, so your problem is solved at the bottom of your programming. :)
Create a ProductList class that has an ArrayList field and a integer set to keep track of ID's that have been added. When you add an item, check if the set already contains the item's ID. If it doesn't, add the item to the ArrayList. So this basically wraps around an ArrayList quite nicely. Here's how I would do it:
public class ProductList{
...
private ArrayList<Product> list = new ArrayList<Product>();
private Set<Integer> ids = new Set<Integer>();
...
public void addProduct(Product product){
if(!ids.contains(product.getID())){
list.add(product);
ids.add(product.getID());
}
}
public Product removeProduct(Product product){
if(!list.contains(product)) return null;
ids.remove(product.getID());
return list.remove(product);
}
...
}
You can then just use
ProductList stock = new ProductList();
and stock.addProduct(Product item); in your other class.
If you think you'll be using your list quite extensively, creating practical constructors to integrate with your data fields will be very useful as well.
This is a very good approach from an abstraction point of view, however it's probably not the most efficient way of doing it.

Categories