2016-01-24 3 views
0

Недавно я просмотрел TripAdvisor для некоторых данных обзора и в настоящее время имеет набор данных со следующей структурой.Удалите повторяющуюся строку из файла CSV на основе строки - JAVA

Organization,Address,Reviewer,Review Title,Review,Review Count,Help Count,Attraction Count,Restaurant Count,Hotel Count,Location,Rating Date,Rating 

Temple of the Tooth (Sri Dalada Maligawa),Address: Sri Dalada Veediya Kandy 20000 Sri Lanka,WowLao,Temple tour,Visits to places of worship always bring home to me the power of superstition. The Temple of the Tooth was no exception. But I couldn't help but marvel at the fervor with which some devotees were praying. One tip though: the shrine that houses the Tooth is open only twice a day and so it's best to check these timings ... More,89,48,7,0,0,Vientiane,2 days ago,3 

Temple of the Tooth (Sri Dalada Maligawa),Address: Sri Dalada Veediya Kandy 20000 Sri Lanka,WowLao,Temple tour,Visits to places of worship always bring home to me the power of superstition. The Temple of the Tooth was no exception. But I couldn't help but marvel at the fervor with which some devotees were praying. One tip though: the shrine that houses the Tooth is open only twice a day and so it's best to check these timings though I would imagine that the crowds would be at a peak.,89,48,7,0,0,Vientiane,2 days ago,3 

Как вы можете видеть, первый ряд объектов имеет частичный обзор, где, как второй ряд имеет полный обзор.

Что я хочу достичь, это проверить дубликаты, подобные этому, и удалить объект (строку), который имеет частичный обзор, и сохранить строку, которая имеет полный обзор.

Я вижу, что каждый частичный обзор заканчивается на «More» в конце, может ли это как-то использоваться для фильтрации частичных обзоров?

Как это сделать с помощью OpenCSV?

+0

Как будет выглядеть файл, если в обзоре есть запятая? – thst

+0

@thth скребок написан таким образом, что любые запятые внутри обзоров удаляются. –

ответ

1

Примечание: Нецелесообразно коммерчески использовать данные другого веб-сервиса без явного разрешения.

Сказав это: В принципе, openCSV предоставит вам список массивов. Массивы - это ваши линии.

Вам нужно скопировать свои строки в другую, более семантическую структуру данных. Судя по вашим строкам заголовка, я бы создал такой bean-компонент.

public class TravelRow { 
    String organization; 
    String address; 
    String reviewer; 
    String reviewTitle; 
    String review; // you get it... 

    public TravelRow(String[] row) { 
     // assign row-index to property 
     this.organization = row[0]; 
     // you get it ... 
    } 
} 

Вы можете генерировать getXXX и setXXX функции для него.

Теперь вам нужно найти первичный ключ для строки, я предлагаю это organisation. Итерации по строкам, создание компонента для него, добавление его в хэш-карту с организацией ключа.

Если организация уже находится в hashmap, вы сравниваете текущий обзор с уже сохраненным обзором. Если новый обзор длиннее или сохраненный заканчивается ... more, вы заменяете объект на карте.

После повторения всех строк у вас есть Map с отзывами, которые вы хотите.

Map<TravelRow> result = new HashMap<TravelRow>(); 
CSVReader reader = new CSVReader(new FileReader("yourfile.csv")); 
String [] nextLine; 
while ((nextLine = reader.readNext()) != null) { 
    // nextLine[] is an array of values from the line 
    if(result.containsKey(nextLine[0])) { 
     // compare the review 
     if(reviewNeedsUpdate(result.get(nextLine[0]), nextLine[4])) { 
      result.get(nextLine[0]).setReview(nextLine[4]); // update only the review, create a new object, if you like 
     } 
    } 
    else { 
     // create TravelRow with array using the constructor eating the line 
     result.put(nextLine[0], new TravelRow(nextLine)); 
    } 
} 

reviewNeedsUpdate(TravelRow row, String review) будет сравнивать review с row.review и вернуть true, если новый обзор лучше. Вы можете расширить эту функцию до тех пор, пока не соответствует вашим потребностям ....

private boolean reviewNeedsUpdate(TravelRow row, String review) { 
    return (row.review.endsWith("more") && !review.endsWith("more")); 
} 
+0

Спасибо. Мне удалось сделать это, отредактировав фрагмент кода, который вы предоставили. :) –

0

Как о следующем:

HashMap<String, String[]> preferredReviews = new HashMap<>(); 
int indexOfReview = 4; 
CSVReader reader = new CSVReader(new FileReader("reviews.csv")); 
String [] nextLine; 
while ((nextLine = reader.readNext()) != null) { 
    String reviewId = nextLine[0]; 
    String[] prevReview = preferredReviews.get(reviewId); 
    if (prevReview == null || prevReview[indexOfReview].length < nextLine[indexOfReview].length) { 
     preferredReviews.put(reviewId, nextLine); 
    } 
} 

Во втором пункте заявления, если он делает сравнение длины, чтобы решить, какой идти с. Что мне нравится в этом подходе, так это то, что если по какой-то причине полного обзора размера нет, то по крайней мере вы получите короткий.

Но его можно изменить, чтобы проверить «... больше» вместо длины обзора.

HashMap<String, String[]> preferredReviews = new HashMap<>(); 
int indexOfReview = 4; 
CSVReader reader = new CSVReader(new FileReader("reviews.csv")); 
String [] nextLine; 
while ((nextLine = reader.readNext()) != null) { 
    String reviewId = nextLine[0]; 
    if (nextLine[indexOfReview].endsWith("... More")){ 
     preferredReviews.put(reviewId, nextLine); 
    }  
} 
+1

Судя по названиям столбцов, 'indexOfReview' -' 4', '3' - это заголовок. – thst

0

Скажем, вы определяете класс Rating для хранения соответствующих данных.

class Rating { 
    public String review; // consider using getters/setters instead of public fields 

    Rating(String review) { 
    this.review = review; 
    } 
} 

Считать содержимое CSV.

Set<Rating> readCSV() { 
    List<String[]> csv = new CSVReader(new FileReader("reviews.csv")).readAll(); 
    List<Rating> ratings = csv.stream() 
     .map(row -> new Rating(row[4])) // add the other attributes 
     .collect(Collectors.toList()); 
    return mergeRatings(ratings); 
} 

Мы будем использовать TreeSet разобраться дубликатов. Для этого требуется настраиваемый компаратор, который отбрасывает элементы, которые уже находятся в наборе.

class RatingMergerComparator implements Comparator<Rating> { 

    @Override 
    public int compare(Rating rating1, Rating rating2) { 
    if (rating1.review.startsWith(rating2.review) || 
     rating2.review.startsWith(rating1.review)) { 
     return 0; 
    } 
    return rating1.review.compareTo(rating2.review); 
    } 
} 

Создать mergeRatings метод

void removeMoreEndings(List<Ratings> ratings) { 
    for (Rating rating : ratings) { 
    if (rating.review.endsWith("... More")) { 
     rating.review = rating.review.substring(0, rating.review.length() - 9); // 9 = length of "... More" 
    } 
    } 
} 

Set<Rating> mergeRatings(List<Rating> ratings) { 
    removeMoreEndings(ratings); // remove all "... More" endings 
    // sort ratings by length in a descending order, since the set will discard certain items, 
    // it is important to keep the longer ones, so they come first 
    ratings.sort(Comparator.comparing((Rating rating) -> rating.review.length()).reversed()); 
    TreeSet<Rating> mergedRatings = new TreeSet<>(new RatingMergerComparator()); 
    mergedRatings.addAll(ratings); 
    return mergedRatings; 
} 

UPDATE

я, возможно, неправильно ОП. Вышеупомянутое решение дает очень хорошую производительность, даже если записи, которые должны быть объединены, находятся дальше в CSV. Если вы уверены, частичные полные обзоры являются последовательными, вышеуказанное может быть излишним.

0

Это зависит от того, как вы читаете данные.

Если вы читаете данные как бобы, используя MappingStategy, вы можете создать свой собственный фильтр с помощью интерфейса CSVFilter и ввести его в класс CsvToBean. Это приводит к тому, что строка должна быть прочитана (разрешена) или пропущена на основе критериев в методе allowedLine. Java docs для CSVFilter дает отличный пример - для вашего случая вы разрешаете все строки, чей столбец обзора не заканчивается «Больше».

Если вы используете CSVReader/CSVParser, это будет немного сложнее. Вам нужно будет прочитать заголовок и посмотреть, в каком столбце находится обзор. Затем, читая каждую строку, вы будете смотреть на элемент в этом индексе, и если он заканчивается в «Больше», не обрабатывайте его.

Смежные вопросы