在Java中计算列表中每个唯一元素的关键字密度?
我能够使用以下代码计算文本体的关键字密度:在Java中计算列表中每个唯一元素的关键字密度?,java,string,data-structures,hashmap,find-occurrences,Java,String,Data Structures,Hashmap,Find Occurrences,我能够使用以下代码计算文本体的关键字密度: HashMap<String, Integer> frequencies = new HashMap<String, Integer>(); String[] splitTextArr = StringX.splitStrIntoWordsRtrnArr(text); int articleWordCount = splitTextArr.length; for (String splitText : splitTextA
HashMap<String, Integer> frequencies = new HashMap<String, Integer>();
String[] splitTextArr = StringX.splitStrIntoWordsRtrnArr(text);
int articleWordCount = splitTextArr.length;
for (String splitText : splitTextArr) {
if (frequencies.containsKey(splitText)) {
Integer previousInt = frequencies.get(splitText);
Integer newInt = ++previousInt;
frequencies.put(splitText, newInt);
} else {
frequencies.put(splitText, 1);
}
}
其中,键
表示标题ID(即标题1、标题2等),而值
表示实际标题
每个关键字的原始出现次数(降序,不区分大小写)如下所示:
佳能:2 |鼠标:2 |无线:2 |相机:1 |充电器:1 |照片:1 |打印机:1 |陷阱:1
注意:每个关键字在每个标题中只计算一次。因此,尽管关键词canon出现了3次,但由于它在同一个标题(即标题2)中出现了两次,因此只计算了一次
在前面的地图中
,标题1和标题2中都出现了关键词canon。因为每个标题都需要用一个关键字来表示,所以两个标题都可以用关键字canon来表示。不必包含标题1和标题2中的其他关键字(例如:照片、打印机和照相机),因为每个标题应仅由一个关键字(不多,不少)表示。尽管我们可以选择使用关键字photo和camera(或printer和camera)来表示标题1和标题2,但由于这会增加表示所有标题所需的关键字总数,因此并不需要这样做。换句话说,我们希望用尽可能少的关键字来表示所有标题
重要的部分是提取能够一次“表示”列表中所有标题的最少数量的关键字,并跟踪每个关键字链接到的标题数量和标题ID。如果不是5个标题,而是100个标题的列表,其中关键字照片出现95次(即,比关键字佳能出现的次数多),则关键字照片将用于替换关键字佳能,标题2将由关键字照相机表示
如果两个或多个关键字可以代表相同数量的标题,我们将按字母顺序选择第一个关键字。因此,关键字鼠标将用于表示标题title3和title5,而不是关键字wireless。同样,为了表示标题4,将使用关键字charger,因为字母表中字母C位于字母W之前(这是正确的,即使关键字wireless出现两次,而关键字充电器只出现一次,因为包含关键字wireless的标题3已经由关键字鼠标而不是关键字wireless表示,因此当两个关键字表示相同数量的标题时,我们恢复使用字母表中的第一个关键字)
在前面的5个标题示例中,预期输出的格式如下:
LinkedHashMap<String, LinkedHashMap<Integer, ArrayList<String>> map = new LinkedHashMap<String, LinkedHashMap<Integer, ArrayList<String>>();
LinkedHashMap基本上,您需要创建某种类型的数据结构,在其中您需要跟踪关键字、链接到的标题数量以及与之关联的标题ID;如下所示:
[canon, {2, [ title1, title2 ] } ]
如果是这种情况,至少有两个原因是不好的:
使用计数作为键是错误的,因为计数将对其他元素重复
您可以通过返回给定关键字的标题ID列表的大小或长度来简单地计算计数
我提出的解决方案有两个方面:使用一个类捕获关键字和标题ID映射,然后使用一组映射对象
班级
使用树形图有必要按照条目的键按自然顺序排列条目
我创建了这个简单的main方法来演示这个实现
public static void main (String[] args) {
List<String> titles = List.of("title2: canon camera canon",
"title3: wireless mouse",
"title1: canon photo printer",
"title4: wireless charger", "title5: mouse trap");
MasterMap mappings = new MasterMap(); // A class wrapping TreeMap<String, KeywordMapping> mappings (the code is shown later on)
for (String title : titles) {
String[] tokens = title.split(": ");
Set<String> keywords = new HashSet<>(Arrays.asList(tokens[1].split(" ")));
for (String keyword : keywords) {
KeywordMapping km = mappings.get(keyword); // don't create duplicate keyword mapping objects
if (km == null) {
km = new KeywordMapping(keyword, tokens[0]);
}
km.addTitleId(tokens[0]);
km.incrementFrequency(keyword);
mappings.put(keyword, km); // update existing or new keyword mapping entry
}
}
System.out.println(mappings);
System.out.println("First entry: " + mappings.firstMapping());
System.out.println("First title in first entry: " + mappings.firstMapping().getValue().getFirstTitleId());
}
请注意,即使原始标题列表不是自然顺序,在插入到关键字映射
对象后,支持标题ID列表的集合是如何按顺序排列它们的。这与树映射中条目的打印顺序相同
最后,每个标题的频率计数只增加一次,因为标题ID列表由集合而不是列表支持,Java中的集合不允许重复。因此,对于标题2:canon camera canon
这样的情况,关键字canon
只计算一次,因为对于该标题一组关键字只有{cannon,camera}
包装树映射以增加功能
这是因为与“title3”{mouse,wireless}
相关联的两个关键字具有相同的频率(2),但“mouse”是按字母顺序排列的集合中的第一个关键字。通过使用正确的术语引用事物来消除混淆。而不是“first String”和“second String”,将它们分别称为键和值。此外,此解释非常复杂。请尽可能多地对其进行总结。@hfontanez感谢您的建设性反馈!我更新了术语并尝试增强总结。希望它能让事情更清楚一些。没问题。我正在研究解决方案。我应该准备好它如果没有打扰,很快就可以了。:)我发布了我的解决方案。我希望我正确理解了您的要求。@感谢您极其详细和翔实的回复!我认为剩下的唯一要求是删除表示标题的关键字,该标题已经由另一个关键字表示。例如,关键字“photo”应该删除,因为标题1由关键字“canon”表示。同样的想法也适用于关键字“打印机”。仅当关键字表示的标题未由其他关键字表示时,才应将其包含在结果中。。(续)@alpha1我正要发布一个更新,如果你想要更多的“元数据”功能,你应该将映射TreeMap
包装在一个类中,并添加你想要的方法。例如,如果标题ID为title2
,则getKeywordsByTitle(String titleId)
应返回{camera,canon}
。同样,你应该能够创建另一种方法来减少或细化你的地图与该要求。(续)如果两个或两个以上的关键字可以代表相同的标题(佳能vs照片),我们选择出现的一个
[canon, {2, [ title1, title2 ] } ]
public class KeywordMapping implements Comparable<KeywordMapping> {
private final String keyword;
private TreeSet<String> titleIds = new TreeSet<String>();
private int frequency;
public KeywordMapping(String keyword, String titleId) {
this.keyword = keyword;
titleIds.add(titleId);
}
public String getKeyword () {
return keyword;
}
public int getTitleCount () {
return titleIds.size();
}
public void addTitleId (String titleId) {
titleIds.add(titleId);
}
public String getFirstTitleId () {
return titleIds.first();
}
public void incrementFrequency(String keyword) {
if (this.keyword.equals(keyword)) {
frequency++;
}
}
public int getFrequency() {
return frequency;
}
public boolean containsTitle(String titleId) {
return titleIds.contains(titleId);
}
@Override
public int hashCode () {
final int prime = 31;
int result = 1;
result = prime * result + ( (keyword == null) ? 0 : keyword.hashCode());
result = prime * result + ( (titleIds == null) ? 0 : titleIds.hashCode());
return result;
}
@Override
public boolean equals (Object obj) {
if (this == obj) return true;
if (obj == null) return false;
if (getClass() != obj.getClass()) return false;
KeywordMapping other = (KeywordMapping) obj;
if (keyword == null) {
if (other.keyword != null) return false;
} else if (!keyword.equals(other.keyword)) return false;
if (titleIds == null) {
if (other.titleIds != null) return false;
} else if (!titleIds.equals(other.titleIds)) return false;
return true;
}
@Override
public String toString () {
return "KeywordMapping [keyword=" + keyword + ", titleIds=" + titleIds + ", frequency=" + frequency
+ "]\n";
}
@Override
public int compareTo (KeywordMapping o) {
return COMPARATOR.compare(this, o);
}
private static final Comparator<KeywordMapping> COMPARATOR =
Comparator.comparing( (KeywordMapping keyMapping) -> keyMapping.keyword);
}
TreeMap<String, KeywordMapping> mappings = new TreeMap<>();
public static void main (String[] args) {
List<String> titles = List.of("title2: canon camera canon",
"title3: wireless mouse",
"title1: canon photo printer",
"title4: wireless charger", "title5: mouse trap");
MasterMap mappings = new MasterMap(); // A class wrapping TreeMap<String, KeywordMapping> mappings (the code is shown later on)
for (String title : titles) {
String[] tokens = title.split(": ");
Set<String> keywords = new HashSet<>(Arrays.asList(tokens[1].split(" ")));
for (String keyword : keywords) {
KeywordMapping km = mappings.get(keyword); // don't create duplicate keyword mapping objects
if (km == null) {
km = new KeywordMapping(keyword, tokens[0]);
}
km.addTitleId(tokens[0]);
km.incrementFrequency(keyword);
mappings.put(keyword, km); // update existing or new keyword mapping entry
}
}
System.out.println(mappings);
System.out.println("First entry: " + mappings.firstMapping());
System.out.println("First title in first entry: " + mappings.firstMapping().getValue().getFirstTitleId());
}
camera=KeywordMapping [keyword=camera, titleIds=[title2], frequency=1]
canon=KeywordMapping [keyword=canon, titleIds=[title1, title2], frequency=2]
charger=KeywordMapping [keyword=charger, titleIds=[title4], frequency=1]
mouse=KeywordMapping [keyword=mouse, titleIds=[title3, title5], frequency=2]
photo=KeywordMapping [keyword=photo, titleIds=[title1], frequency=1]
printer=KeywordMapping [keyword=printer, titleIds=[title1], frequency=1]
trap=KeywordMapping [keyword=trap, titleIds=[title5], frequency=1]
wireless=KeywordMapping [keyword=wireless, titleIds=[title3, title4], frequency=2]
First entry: camera=KeywordMapping [keyword=camera, titleIds=[title2], frequency=1]
First title in first entry: title2
public class MasterMap {
private TreeMap<String, KeywordMapping> mappings = new TreeMap<>();
public KeywordMapping put(String key, KeywordMapping value) {
return mappings.put(key, value);
}
public KeywordMapping get(String key) {
return mappings.get(key);
}
public KeywordMapping firstMapping() {
return mappings.firstEntry().getValue();
}
public String getKeywordForTitle (String titleId) {
List<KeywordMapping> keywords = new ArrayList<>();
Collection<KeywordMapping> values = mappings.values();
Iterator<KeywordMapping> iter = values.iterator();
while (iter.hasNext()) {
KeywordMapping value = iter.next();
if (value.containsTitle(titleId)) {
keywords.add(value);
}
}
KeywordMapping temp = keywords.stream()
.max(Comparator.comparingInt(KeywordMapping::getFrequency)
.thenComparing(KeywordMapping::getKeyword).reversed())
.get();
return temp.getKeyword();
}
}
Keyword for title3: mouse