Comparing ENUMs in Java 6 - enums

I am trying to find best way to compare Enums in Java 6.
Say, I have an ENUM of Ticket Types which can be associated with a Traveler. If there is a list of travelers, I would like to know the traveler with the highest class of travel.
I can iterate thru the list of travelers, create a Set of unique TicketTypes, Convert to List, Sort them, Return the last element as the highest. I would like to know if there is a better way to do this?
public enum TicketType {
ECONOMY_NON_REF(1,"Economy Class, Non-Refundable"),
ECONOMY_REF(2,"Economy Full Fare Refundable"),
BUSINESS(3,"Business Class"),
FIRST_CLASS(4,"First Class, Top of the world");
private String code;
private String description;
}
public class Traveler {
private TicketType ticketType;
public Traveler(TicketType ticketType) {
this.ticketType = ticketType;
}
}
#Test
public testCompareEnums{
List<Traveler> travelersGroup1 = new ArrayList<Travelers>();
travelersGroup1.add(new Traveler(TicketType.ECONOMY_REF));
travelersGroup1.add(new Traveler(TicketType.BUSINESS));
travelersGroup1.add(new Traveler(TicketType.ECONOMY_REF));
travelersGroup1.add(new Traveler(TicketType.ECONOMY_NON_REF));
//What is the best way to find the highest class passenger in travelersGroup1.
assertEquals(TicketType.BUSINESS, getHighestClassTravler(travelersGroup1));
List<Traveler> travelersGroup2 = new ArrayList<Travelers>();
travelersGroup2.add(new Traveler(TicketType.ECONOMY_REF));
travelersGroup2.add(new Traveler(TicketType.ECONOMY_NON_REF));
travelersGroup2.add(new Traveler(TicketType.ECONOMY_REF));
travelersGroup2.add(new Traveler(TicketType.ECONOMY_NON_REF));
assertEquals(TicketType.ECONOMY_REF, getHighestClassTravler(travelersGroup2));
}
private CredentialType getHighestClassTraveler(List travelers){
Set uniqueTicketTypeSet = new HashSet();
for (Traveler t: travelers) {
uniqueTicketTypeSet.add(t.getTicketType());
}
List<TicketType> uniqueTicketTypes = new ArrayList<TicketType>(uniqueTicketTypeSet);
Collections.sort(uniqueTicketTypes);
return uniqueTicketTypes.get(uniqueTicketTypes.size()-1);
}

There's a lot of problems with the code that you posted (it won't compile without fixing a lot of errors), but the easiest way is to make Traveler implement the Comparable interface, like so:
public int compareTo(Traveler other) {
return this.getTicketType().compareTo(other.getTicketType());
}
Then to find the the Traveler with the highest TicketType, you can simply do:
Collections.max(travelers);

Related

How to filter object lists and create another filtered lists from it

I receive a List of MediaDTO and this Object has two attributes:
String sizeType and String URL.
In 'sizeType' comes the image´s size: small, medium, large, and thumbnail.
So I have to filter the sizeType of these objects and create 4 new lists based on them.
This is how I get the List<MediaDTO> mediaDTO:
medias=[MediaDTO(sizeType=THUMBNAIL, liveloUrl=https://s3.sao01.cloud-object-storage.appdomain.cloud/catalog-media-storage/id-source/productId/skuseller2/thumbnail/celular-iphone-11-azul.png), MediaDTO(sizeType=SMALL, liveloUrl=https://s3.sao01.cloud-object-storage.appdomain.cloud/catalog-media-storage/id-source/productId/skuseller2/small/celular-iphone-11-azul.png), MediaDTO(sizeType=SMALL, liveloUrl=https://s3.sao01.cloud-object-storage.appdomain.cloud/catalog-media-storage/id-source/productId/skuseller2/medium/celular-iphone-11-azul.png), MediaDTO(sizeType=LARGE, liveloUrl=https://s3.sao01.cloud-object-storage.appdomain.cloud/catalog-media-storage/id-source/productId/skuseller2/large/celular-iphone-11-azul.png), MediaDTO(sizeType=THUMBNAIL, liveloUrl=https://s3.sao01.cloud-object-storage.appdomain.cloud/catalog-media-storage/id-source/productId/skuseller2/thumbnail/celular-iphone-11-vermelho.png), MediaDTO(sizeType=SMALL, liveloUrl=https://s3.sao01.cloud-object-storage.appdomain.cloud/catalog-media-storage/id-source/productId/skuseller2/small/celular-iphone-11-vermelho.png), MediaDTO(sizeType=MEDIUM, liveloUrl=https://s3.sao01.cloud-object-storage.appdomain.cloud/catalog-media-storage/id-source/productId/skuseller2/medium/celular-iphone-11-vermelho.png), MediaDTO(sizeType=LARGE, liveloUrl=https://s3.sao01.cloud-object-storage.appdomain.cloud/catalog-media-storage/id-source/productId/skuseller2/large/celular-iphone-11-vermelho.png)]
I achieved filtering for one of the sizes. This works!
However, I could not figure out how can I filter over the 4 sizes and create 4 new lists of it.
If I fix some error another appears ... so I´m really stuck.
And by the way I´ve been searching for a solution on the internet and in the forum for a couple of days but did´nt find something that fits.
If someone might help, I´d really be grateful.
I was thinking about using a 'forEach' to filter but even like that, I could filter just one size.
Thanks in advance.
**This is what I got till now: **
public class ProcessProductDTO {
String processId;
OperationProcess operation;
String categoryId;
ProductDTO productDTO;
}
public class ProductDTO {
String id;
Boolean active;
String displayName;
String longDescription;
List<MediaDTO> medias;
List<AttributeDTO> attributes;
}
public class MediaDTO {
String sizeType;
String liveloUrl;
}
public Properties toOccProductPropertiesDTO(ProcessProductDTO processProductDTO) throws JsonProcessingException {
String pSpecs = convertAttributes(processProductDTO.getProductDTO().getAttributes());
//List<String> medias = convertMedias(processProductDTO.getProductDTO().getMedias());
return Properties.builder()
.id(processProductDTO.getProductDTO().getId()) .active(processProductDTO.getProductDTO().getActive())
.listPrices(new HashMap())
.p_specs(pSpecs)
//.medias(medias)
.displayName(processProductDTO.getProductDTO()
.getDisplayName())
.longDescription(processProductDTO.getProductDTO().getLongDescription())
.build(); }
private String convertAttributes(List<AttributeDTO> attributes) throws JsonProcessingException {
Map<String, String> attribs = attributes.stream()
.collect(Collectors.toMap(AttributeDTO::getName, AttributeDTO::getValue));
return objectMapper.writeValueAsString(attribs);
}
private List<MediaDTO> convertMedias(ProcessProductDTO processProduct, List<MediaDTO> mediaDTO){
List<MediaDTO> filteredList = processProduct.getProductDTO().getMedias();
Set<String> filterSet = mediaDTO.stream().map(MediaDTO::getSizeType).collect(Collectors.toSet());
return filteredList.stream().filter(url -> filterSet.contains("SMALL")).collect(Collectors.toList());
}
UPDATE
I got the following result:
private Properties toOccProductPropertiesDTO(ProcessProductDTO processProductDTO) throws JsonProcessingException {
String pSpecs = convertAttributes(processProductDTO.getProductDTO().getAttributes());
MediaOccDTO medias = convertMedias(processProductDTO.getProductDTO().getMedias());
return Properties.builder()
.id(processProductDTO.getProductDTO().getId())
.active(processProductDTO.getProductDTO().getActive())
.listPrices(new HashMap())
.p_specs(pSpecs)
.medias(medias)
.displayName(processProductDTO.getProductDTO().getDisplayName())
.longDescription(processProductDTO.getProductDTO().getLongDescription())
.build();
}
private MediaOccDTO convertMedias(List<MediaDTO> mediaDTOs){
String smallImageUrls = generateOccUrl(mediaDTOs, ImageSizeType.SMALL);
String mediumImageUrls = generateOccUrl(mediaDTOs, ImageSizeType.MEDIUM);
String largeImageUrls = generateOccUrl(mediaDTOs, ImageSizeType.LARGE);
String thumbImageUrls = generateOccUrl(mediaDTOs, ImageSizeType.THUMB);
return MediaOccDTO.builder()
.p_smallImageUrls(smallImageUrls)
.p_mediumImageUrls(mediumImageUrls)
.p_largeImageUrls(largeImageUrls)
.p_thumbImageUrls(thumbImageUrls)
.build();
}
private String generateOccUrl(List<MediaDTO> mediaDTOs, ImageSizeType imageSizeType){
return mediaDTOs.stream()
.filter(m -> m.getSizeType().equals(imageSizeType))
.map(MediaDTO::getLiveloUrl)
.reduce(",", String::concat);
}
The problem is:
the comparison: m.getSizeType().equals(imageSizeType)
is always false, so the list gets created empty...
Though the question is laborious, I could think of the requirement being, you need to create 4 new lists based on sizeType.
Stream collector, can collect the results to a single data structure. It can be a list, set, Map etc.
Since you need 4 lists based on sizeType, you will need to pass through the stream 4 times to create 4 lists.
Another Alternate will be to create a Map<SizeType, List<MediaDTO>>
This can be achieved through,
mediaDTO.stream().collect(Collectors.toMap(i -> i.getSizeType(), i->i)
I think the toMap doesn't collect the values in a list. We need groupingBy instead.
mediaDTO.stream()
.collect(Collectors.groupingBy(MediaDTO::getSizeType));

A algorithm to track the status of a number

To design a API,
get(), it will return the random number, also the number should not duplicate, means it always be unique.
put(randomvalue), it will put back the generated random number from get(), if put back, get() function can reuse this number as output.
It has to be efficient, no too much resource is highly used.
Is there any way to implement this algorithm? It is not recommended to use hashmap, because if this API generate for billions of requests, saving the generated the random number still use too much space.
I could no work out this algorithm, please help give a clue, thanks in advance!
I cannot think of any solution without extra space. With space, one option could be to use TreeMap, firstly add all the elements in treeMap with as false. When element is accessed, mark as true. Similarly for put, change the value to false.
Code snippet below...
public class RandomNumber {
public static final int SIZE = 100000;
public static Random rand;
public static TreeMap<Integer, Boolean> treeMap;
public RandomNumber() {
rand = new Random();
treeMap = new TreeMap<>();
}
static public int getRandom() {
while (true) {
int random = rand.nextInt(SIZE);
if (!treeMap.get(random)) {
treeMap.put(random, true);
return random;
}
}
}
static public void putRandom(int number) {
treeMap.put(number, false);
}
}

Tranversing and filtering a Set comparing its objects' getters to an Array using Stream

I've got some working, inelegant code here:
The custom object is:
public class Person {
private int id;
public getId() { return this.id }
}
And I have a Class containing a Set<Person> allPersons containing all available subjects. I want to extract a new Set<Person> based upon one or more ID's of my choosing. I've written something which works using a nested enhanced for loop, but it strikes me as inefficient and will make a lot of unnecessary comparisons. I am getting used to working with Java 8, but can't quite figure out how to compare the Set against an Array. Here is my working, but verbose code:
public class MyProgram {
private Set<Person> allPersons; // contains 100 people with Ids 1-100
public Set<Person> getPersonById(int[] ids) {
Set<Person> personSet = new HashSet<>() //or any type of set
for (int i : ids) {
for (Person p : allPersons) {
if (p.getId() == i) {
personSet.add(p);
}
}
}
return personSet;
}
}
And to get my result, I'd call something along the lines of:
Set<Person> resultSet = getPersonById(int[] intArray = {2, 56, 66});
//resultSet would then contain 3 people with the corresponding ID
My question is how would i convert the getPersonById method to something using which streams allPersons and finds the ID match of any one of the ints in its parameter array? I thought of some filter operation, but since the parameter is an array, I can't get it to take just the one I want only.
The working answer to this is:
return allPersons.stream()
.filter(p -> (Arrays.stream(ids).anyMatch(i -> i == p.getId())) )
.collect(Collectors.toSet());
However, using the bottom half of #Flown's suggestion and if the program was designed to have a Map - it would also work (and work much more efficiently)
As you said, you can introduce a Stream::filter step using a Stream::anyMatch operation.
public Set<Person> getPersonById(int[] ids) {
Objects.requireNonNull(ids);
if (ids.length == 0) {
return Collections.emptySet();
}
return allPersons.stream()
.filter(p -> IntStream.of(ids).anyMatch(i -> i == p.getId()))
.collect(Collectors.toSet());
}
If the method is called more often, then it would be a good idea to map each Person to its id having a Map<Integer, Person>. The advantage is, that the lookup is much faster than iterating over the whole set of Person.Then your algorithm may look like this:
private Map<Integer, Person> idMapping;
public Set<Person> getPersonById(int[] ids) {
Objects.requireNonNull(ids);
return IntStream.of(ids)
.filter(idMapping::containsKey)
.mapToObj(idMapping::get)
.collect(Collectors.toSet());
}

How to select objects from a list that has a property that matches an item in another list?

Hard question to understand perhaps, but let me explain. I have a List of Channel-objects, that all have a ChannelId property (int). I also have a different List (int) - SelectedChannelIds, that contains a subset of the ChannelId-s.
I want to select (through LINQ?) all the Channel-objects that has a ChannelId-property matching one in the second List.
in other words, I have the following structure:
public class Lists
{
public List<Channel> AllChannels = ChannelController.GetAllChannels();
public List<int> SelectedChannelIds = ChannelController.GetSelectedChannels();
public List<Channel> SelectedChannels; // = ?????
}
public class Channel
{
// ...
public int ChannelId { get; set; }
// ...
}
Any ideas on what that LINQ query would look like? Or is there a more effective way? I'm coding for the Windows Phone 7, fyi.
You can use List.Contains in a Where clause:
public Lists()
{
SelectedChannels = AllChannels
.Where(channel => SelectedChannelIds.Contains(channel.ChannelId))
.ToList();
}
Note that it would be more efficient if you used a HashSet<int> instead of a List<int> for the SelectedChannelIds. Changing to a HashSet will improve the performance from O(n2) to O(n), though if your list is always quite small this may not be a significant issue.
SelectedChannels = new List<Channel>(AllChannels.Where(c => SelectedChannelIds.Contains(c.ChannelId)));

IList with an implicit sort order

I'd like to create an IList<Child> that maintains its Child objects in a default/implicit sort order at all times (i.e. regardless of additions/removals to the underlying list).
What I'm specifically trying to avoid is the need for all consumers of said IList<Child> to explicitly invoke IEnumerable<T>.OrderBy() every time they want to enumerate it. Apart from violating DRY, such an approach would also break encapsulation as consumers would have to know that my list is even sorted, which is really none of their business :)
The solution that seemed most logical/efficient was to expose IList<Child> as IEnumerable<Child> (to prevent List mutations) and add explicit Add/Remove methods to the containing Parent. This way, I can intercept changes to the List that necessitate a re-sort, and apply one via Linq:
public class Child {
public string StringProperty;
public int IntProperty;
}
public class Parent{
private IList<Child> _children = new List<Child>();
public IEnumerable<Child> Children{
get
{
return _children;
}
}
private void ReSortChildren(){
_children = new List<Child>(child.OrderBy(c=>c.StringProperty));
}
public void AddChild(Child c){
_children.Add();
ReSortChildren()
}
public void RemoveChild(Child c){
_children.Remove(c);
ReSortChildren()
}
}
Still, this approach doesn't intercept changes made to the underlying Child.StringProperty (which in this case is the property driving the sort). There must be a more elegant solution to such a basic problem, but I haven't been able to find one.
EDIT:
I wasn't clear in that I would preferable a LINQ compatible solution. I'd rather not resort to using .NET 2.0 constructs (i.e. SortedList)
What about using a SortedList<>?
One way you could go about it is to have Child publish an event OnStringPropertyChanged which passes along the previous value of StringProperty. Then create a derivation of SortedList that overrides the Add method to hookup a handler to that event. Whenever the event fires, remove the item from the list and re-add it with the new value of StringProperty. If you can't change Child, then I would make a proxy class that either derives from or wraps Child to implement the event.
If you don't want to do that, I would still use a SortedList, but internally manage the above sorting logic anytime the StringProperty needs to be changed. To be DRY, it's preferable to route all updates to StringProperty through a common method that correctly manages the sorting, rather than accessing the list directly from various places within the class and duplicating the sort management logic.
I would also caution against allowing the controller to pass in a reference to Child, which allows him to manipulate StringProperty after it's added to the list.
public class Parent{
private SortedList<string, Child> _children = new SortedList<string, Child>();
public ReadOnlyCollection<Child> Children{
get { return new ReadOnlyCollection<Child>(_children.Values); }
}
public void AddChild(string stringProperty, int data, Salamandar sal){
_children.Add(stringProperty, new Child(stringProperty, data, sal));
}
public void RemoveChild(string stringProperty){
_children.Remove(stringProperty);
}
private void UpdateChildStringProperty(Child c, string newStringProperty) {
if (c == null) throw new ArgumentNullException("c");
RemoveChild(c);
c.StringProperty = newStringProperty;
AddChild(c);
}
public void CheckSalamandar(string s) {
if (_children.ContainsKey(s))
var c = _children[s];
if (c.Salamandar.IsActive) {
// update StringProperty through our method
UpdateChildStringProperty(c, c.StringProperty.Reverse());
// update other properties directly
c.Number++;
}
}
}
I think that if you derive from KeyedCollection, you'll get what you need. That is only based on reading the documentation, though.
EDIT:
If this works, it won't be easy, unfortunately. Neither the underlying lookup dictionary nor the underlying List in this guy is sorted, nor are they exposed enough such that you'd be able to replace them. It might, however, provide a pattern for you to follow in your own implementation.

Resources