我从两个不同的书店获得了2个书名清单。这些标题可以相同,但是写法不同,例如“例如”-“例如-”,因为您可以看到它们是相等的,但根本不相同。
这就是为什么我编写了一个流,该流将从列表中纯化元素(它将删除空格和特殊字母)并使它们相等,因此流之后看起来都像“ forexmaple”,因此它们现在相等。
.scroll-panel {
display: flex;
border: 2px dashed rgba(114, 186, 94, 0.35);
overflow: scroll;
flex-wrap: nowrap;
height: 100%;
-webkit-overflow-scrolling: touch;
max-height: calc(100vh - 42px);
}
问题是...我想获得一张包含原始标题和书籍出现次数的地图(最多2次出现,默认为1次)。 我已经编写了比较两个书名的算法,并从第一个书店向地图添加了书名,但是我必须从第二个书店添加书名,但是不知道如何获得该书名。
说清楚...
我正在比较第一家书店的书名和第二家书店的书名,如果相等,那么我要加+1,如果for循环结束,我要从出现次数的第一家书店中添加该迭代书名。但是第二书店只出现过一次的书名该怎么办?我知道第一家书店的迭代标题的索引,因此我可以使用private List<String> purifyListOfTitles(List<Book> listToPurify) {
return listToPurify
.stream()
.map(Book::getTitle)
.map(title -> title.replaceAll("[^A-Za-z]+", ""))
.collect(Collectors.toList());
}
方法从原始列表中获取该标题(带有未纯化的标题),但是我不知道第二家书店的迭代标题的索引以获得原始标题。
我看到的唯一解决方案是,首先将tite与第二个标题中的每个标题进行比较,然后再将其与第一家书店中的每个标题进行比较,但这不是最佳解决方案...或者以某种方式使列表不纯。
总而言之,我只有第一家书店的地图标题,如何添加第二家书店中被省略的标题。 我想在地图上显示原始标题(例如,纯净的房子很大,但是原始的房屋-大)!我正在与纯净的清单进行比较,并添加原始标题。
课程:
.get(i)
示例:
package bookstore.scraper.rankingsystem;
import bookstore.scraper.Bookstore;
import bookstore.scraper.book.Book;
import bookstore.scraper.book.scrapingtypeservice.CategorizedBookService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import static java.util.stream.Collectors.toMap;
@Slf4j
@Component
public class CategorizedBooksRankingService {
private final CategorizedBookService categorizedBookService;
@Autowired
public CategorizedBooksRankingService(CategorizedBookService categorizedBookService) {
this.categorizedBookService = categorizedBookService;
}
public Map<String, Integer> getRankingForCategory(String category) {
Map<Bookstore, List<Book>> bookstoreWith15CategorizedBooks = chooseGetterImplementationByCategory(category);
List<Book> merlinBooks = bookstoreWith15CategorizedBooks.get(Bookstore.MERLIN);
List<Book> empikBooks = bookstoreWith15CategorizedBooks.get(Bookstore.EMPIK);
List<String> purifiedMerlinBookTitles = purifyListOfTitles(merlinBooks);
List<String> purifiedEmpikBookTitles = purifyListOfTitles(empikBooks);
Map<String, Integer> bookTitleWithOccurrencesNumber =
prepareTitleAndOccurrencesMap(merlinBooks, empikBooks, purifiedMerlinBookTitles, purifiedEmpikBookTitles);
return getSortedLinkedHashMappedByValue(bookTitleWithOccurrencesNumber);
}
private Map<String, Integer> prepareTitleAndOccurrencesMap(List<Book> merlinBooks, List<Book> empikBooks, List<String> purifiedMerlinBookTitles, List<String> purifiedEmpikBookTitles) {
Map<String, Integer> bookTitleWithOccurrencesNumber = new LinkedHashMap<>();
int occurrencesOfIteratedBook;
String iteratedMerlinTitle;
for (int i = 0; i < purifiedMerlinBookTitles.size(); i++) {
occurrencesOfIteratedBook = 1;
iteratedMerlinTitle = purifiedMerlinBookTitles.get(i);
for (String iteratedEmpikTitle : purifiedEmpikBookTitles) {
if (iteratedMerlinTitle.equals(iteratedEmpikTitle))
occurrencesOfIteratedBook++;
}
bookTitleWithOccurrencesNumber.put(merlinBooks.get(i).getTitle(), occurrencesOfIteratedBook);
//how to add to bookTitleWithOccurrencesNumber map book titles from second bookstore that are not equal to any of title
}
return bookTitleWithOccurrencesNumber;
}
private List<String> purifyListOfTitles(List<Book> listToPurify) {
return listToPurify
.stream()
.map(Book::getTitle)
.map(title -> title.replaceAll("[^A-Za-z]+", ""))
.collect(Collectors.toList());
}
private Map<String, Integer> getSortedLinkedHashMappedByValue(Map<String, Integer> mapToSort) {
return mapToSort.entrySet()
.stream()
.sorted(Collections.reverseOrder(Map.Entry.comparingByValue()))
.collect(
toMap(Map.Entry::getKey, Map.Entry::getValue, (e1, e2) -> e2,
LinkedHashMap::new));
}
private Map<Bookstore, List<Book>> chooseGetterImplementationByCategory(String category) {
if (category.equals("crimes"))
return categorizedBookService.get15BooksFromCrimeCategory();
if (category.equals("romances"))
return categorizedBookService.get15BooksFromRomanceCategory();
if (category.equals("fantasies"))
return categorizedBookService.get15BooksFromFantasyCategory();
if (category.equals("guides"))
return categorizedBookService.get15BooksFromGuidesCategory();
if (category.equals("biographies"))
return categorizedBookService.get15BooksFromBiographiesCategory();
else {
log.error(category + " is invalid category");
throw new IllegalArgumentException();
}
}
}
z Book a = new Book.BookBuilder().withTitle("To - jest haha").build();
Book b = new Book.BookBuilder().withTitle("Bubu").build();
Book c = new Book.BookBuilder().withTitle("Kiki").build();
Book d = new Book.BookBuilder().withTitle("sza . la").build();
Book e = new Book.BookBuilder().withTitle("Tojest haha").build();
Book f = new Book.BookBuilder().withTitle("bam").build();
Book g = new Book.BookBuilder().withTitle("zzz").build();
Book h = new Book.BookBuilder().withTitle("szaLa").build();
List<Book> list1 = new ArrayList<>();
list1.add(a);
list1.add(b);
list1.add(c);
list1.add(d);
List<Book> list2 = new ArrayList<>();
list2.add(e);
list2.add(f);
list2.add(g);
list2.add(h);
Map<String,Long> z = countBooksByTitle(list1,list2);
包含:map
答案 0 :(得分:1)
我有2个列表
...
我想得到一张包含书名和出现次数的地图
您可以做到这是一条流链:
private Map<String, Long> countBooksByTitle(List<Book> list1, List<Book> list2) {
return Stream.concat(list1.stream(), list2.stream())
.map(book -> book.getTitle().replaceAll("[^A-Za-z]+", ""))
.collect(Collectors.groupingBy(Function.identity(), Collectors.counting()));
}
请注意,如果列表中有两个或更多不同的书名(标题映射到相同的紧凑文本),则该计数理论上可能会大于2。例如。由于您只保留字母,因此Streams for dummies 1
和Streams for dummies 2
将算作两本标题为Streamsfordummies
的书。
更新
要保留原始标题,请创建一个助手类,该类按纯标题进行比较,但保留原始标题,然后先使用该类构建地图,然后将其解包装为原始标题。
在下面的代码中,对提纯进行了修改以保留数字,并在保留字母的同时消除重音,例如bé
-> be
,而问题代码将消除字母bé
-> b
。这样bé
和bä
就不会比较相等。
由于计数代码仍在映射键/值对,因此该值也从Long
映射到Integer
,只是为了表明它可以完成。生成的地图也已修改为按标题排序。
助手类
public final class PurifiedTitle implements Comparable<PurifiedTitle> {
private final String original;
private final String purified;
public PurifiedTitle(String title) {
this.original = title;
// Purified string has only lowercase letters and digits,
// with no accents on the letters
this.purified = Normalizer.normalize(title, Normalizer.Form.NFD)
.replaceAll("\\P{Alnum}+", "")
.toLowerCase(Locale.US);
}
@Override
public String toString() {
return this.original;
}
@Override
public int compareTo(PurifiedTitle that) {
return this.purified.compareTo(that.purified);
}
@Override
public boolean equals(Object obj) {
if (! (obj instanceof PurifiedTitle))
return false;
PurifiedTitle that = (PurifiedTitle) obj;
return this.purified.equals(that.purified);
}
@Override
public int hashCode() {
return this.purified.hashCode();
}
}
更新的计数方法
private static Map<String, Integer> countBooksByTitle(List<Book> list1, List<Book> list2) {
Collator collator = Collator.getInstance(Locale.US);
collator.setStrength(Collator.PRIMARY);
return Stream.concat(list1.stream(), list2.stream())
.collect(Collectors.groupingBy(book -> new PurifiedTitle(book.getTitle()),
Collectors.counting()))
.entrySet().stream()
.collect(Collectors.toMap(e -> e.getKey().toString(),
e -> e.getValue().intValue(),
Integer::sum,
() -> new TreeMap<>(collator)));
}
测试
List<Book> list1 = Arrays.asList(
new Book("To - jest haha"),
new Book("Bubû"),
new Book("Kiki"),
new Book("bam 2"),
new Book("sza . lä"));
List<Book> list2 = Arrays.asList(
new Book("Tojest haha"),
new Book("bam 1"),
new Book("zzz"),
new Book("száLa"));
System.out.println(countBooksByTitle(list1, list2));
输出
{bam 1=1, bam 2=1, Bubû=1, Kiki=1, sza . lä=2, To - jest haha=2, zzz=1}
答案 1 :(得分:0)
可能的解决方案,对您的算法影响最小:只要它们与第一个列表中的标题匹配,便可以从第二个列表中删除标题。
这样做,第二个列表将仅包含for循环之后不匹配的书。 然后,您可以将所有这些对象添加到出现率为1的地图中。
您应该使用迭代器来浏览列表并删除项目。
for (int i = 0; i < purifiedMerlinBookTitles.size(); i++) {
occurrencesOfIteratedBook = 1;
iteratedMerlinTitle = purifiedMerlinBookTitles.get(i);
Iterator<String> it = purifiedEmpikBookTitles.iterator();
while (it.hasNext()) {
String iteratedEmpikTitle = it.next();
if (iteratedMerlinTitle.equals(iteratedEmpikTitle)) {
occurrencesOfIteratedBook++;
it.remove();
}
}
bookTitleWithOccurrencesNumber.put(merlinBooks.get(i).getTitle(), occurrencesOfIteratedBook);
}
// At this time purifiedEmpikBookTitles contains only unmatched titles
purifiedEmpikBookTitles.forEach(title -> bookTitleWithOccurrencesNumber.put(title, 1));
return bookTitleWithOccurrencesNumber;
}