Problem:
Given a set of words and many review of this hotels, you must display the hotels Ids containing in their reviews the words informed.
Inputs:
– Line 1: words
– Line 2: quantity of reviews
– Line 3 .. N: Id Hotel and review;
Rules :
– Special characters should be disregarded;
– If a word appears more than once it should be told all times;
– The result should be respectively ordered by the number of words found and the id of the hotel.
My solution :
public static class Hotel{
private Integer idHotel;
private Integer score;
public Hotel(Integer idHotel, Integer score){
this.idHotel = idHotel;
this.score = 0;
}
public Integer getScore() {
return score;
}
public Integer getIdHotel() {
return idHotel;
}
@Override
public String toString(){
return this.getIdHotel().toString() + " ";
}
}
public static class Utils{
public static List<String> getArrayOfWordsLine(String words) {
String[] wordsArray = buildWordsArray(words);
return Arrays.asList(wordsArray);
}
private static String[] buildWordsArray(String words) {
words = words.replaceAll("[!,?._'@]", "");
words = words.replaceAll("^ +| +$|( )+", " ");
words = words.replaceAll("^\\s+", "").replaceAll("\\s+$", "");
return words.split(" ");
}
}
public static void main(String[] args) {
Scanner scan = new Scanner(System.in);
String words = scan.nextLine();
Integer nunReviews = scan.nextInt();
List<Hotel> hotelList = new ArrayList<>();
int counter = 0;
while (counter < nunReviews){
Integer hotelId = scan.nextInt();
scan.next();
String stringReview = scan.nextLine();
List<String> arrayWithWordsReview = Utils.getArrayOfWordsLine(stringReview);
Integer score = calcHotelScore(words,arrayWithWordsReview);
hotelList.add(new Hotel(hotelId, score));
counter ++;
}
List<Hotel> answer = takeOrderDescHotelsByQuantityReview(hotelList);
answer.stream().forEach(System.out::print);
}
private static Integer calcHotelScore(String reviews, List<String> wordsArray) {
return wordsArray.stream().filter(s -> reviews.contains(s)).collect(
Collectors.groupingBy(Object::toString,
Collectors.collectingAndThen(
Collectors.mapping(Object::toString, Collectors.toSet()),
Set::size))).values().stream().mapToInt(i -> i.intValue()).sum();
}
private static List<Hotel> takeOrderDescHotelsByQuantityReview(List<Hotel> hotelList) {
List<Hotel> finalList = new ArrayList<>();
hotelList.stream()
.collect(Collectors.groupingBy(h -> h.getIdHotel(),
Collectors.summingInt(h->h.getScore()))).forEach((a,b)->{finalList.add(new Hotel(a,b));});
orderResultsByScoreAndHotelId(finalList);
return finalList;
}
private static void orderResultsByScoreAndHotelId(List<Hotel> finalListHotels) {
Collections.sort(finalListHotels, new Comparator<Hotel>() {
@Override
public int compare(Hotel o1, Hotel o2) {
Integer compare = o2.getScore().compareTo(o1.getScore());
if ( compare == 0){
return o1.getIdHotel().compareTo(o2.getIdHotel());
}
return compare;
}
});
}