给出以下代码:
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.LinkedHashSet;
import java.util.List;
public class FileNameSeq {
public static void main(String[] args) {
//List containing duplicate names
List<String> al = new ArrayList<String>(Arrays.asList("JAVA", "JAVA", "JAVA", "CPP", "JAVA", "CPP" ,"C"));
ArrayList<String> filenameList = new ArrayList<>();
for (int i = 0; al.size() > 0;) {
int freq = Collections.frequency(al, al.get(i));
String fileName = al.get(i);
filenameList.add(fileName.concat("-").concat("" + freq));
al.remove(i); /* removing the element */
}
System.out.println(filenameList);
}
}
我已经开发了这段代码来生成序列,如果列表中存储了类似的名称,那么第一次出现的名称应该附加"-1"
,第二次出现"-2"
,依此类推"-N"
如果没有重复,则名称应保持不变。在运行程序时,我得到以下输出
[JAVA-4, JAVA-3, JAVA-2, CPP-2, JAVA-1, CPP-1, C-1]
但输出应该像
[JAVA-4, JAVA-3, JAVA-2, CPP-2, JAVA-1, CPP-1, C]
C
不应附加"-1"
。
我需要做出哪些更改才能生成以后的输出?
答案 0 :(得分:1)
您必须测试您的收藏中最初只有一次出现。
/**
* @param args
*/
public static void main(String[] args) {
//List containing duplicate names
List<String> al = new ArrayList<String>(Arrays.asList("JAVA", "JAVA", "JAVA", "CPP", "JAVA", "CPP" ,"C"));
ArrayList<String> filenameList = new ArrayList<String>();
//Creates a copy of the collection, which will remain unchanged
List<String> alCopy = new ArrayList<String>(al);
for (int i = 0; al.size() > 0;) {
String fileName = al.get(i);
int freq = Collections.frequency(al,fileName);
boolean toConcat = freq != 1;
if(!toConcat){
//checks if there was actually only one occurrence of filename
//or if it is only the last one
toConcat =( Collections.frequency(alCopy,fileName) != 1);
}
if(toConcat){
filenameList.add(fileName.concat("-").concat("" + freq));
//Why not filenameList.add(fileName + "-" + freq)); ??
} else {
filenameList.add(fileName);
}
al.remove(i); /* removing the element */
}
System.out.println(filenameList);
}
请注意,此代码会生成您在问题中提到的输出
[JAVA-4,JAVA-3,JAVA-2,CPP-2,JAVA-1,CPP-1,C]
如果你想要我建议的输出:
[JAVA-1,JAVA-2,JAVA-3,CPP-1,JAVA-4,CPP-2,C]
您可以使用以下使用地图的代码计算每次出现的文件名。
/**
* @param args
*/
public static void main(String[] args) {
//List containing duplicate names
List<String> al = new ArrayList<String>(Arrays.asList("JAVA", "JAVA", "JAVA", "CPP", "JAVA", "CPP" ,"C"));
ArrayList<String> filenameList = new ArrayList<String>();
Map<String, Integer>counters = new HashMap<String, Integer>();
for(String fileName : al){
Integer count = counters.get(fileName);
boolean toConcat = true;
if(count == null){
//First occurence. Is it the only one?
count = 0;
if(Collections.frequency(al,fileName) == 1){
toConcat = false;
}
}
count += 1;
counters.put(fileName, count);
if(toConcat){
filenameList.add(fileName.concat("-").concat("" + count));
//Why not filenameList.add(fileName + "-" + count)); ??
} else {
filenameList.add(fileName);
}
}
System.out.println(filenameList);
}
请注意,在这种情况下,我们不必修改原始集合,这样更清晰。
修改强>
正如其他人在回答中提到的,第一种解决方案效果不是很好,因为Collection.frequency
总是会扫描整个集合。除此之外,我认为从原始集合中删除元素并不是很干净。
因此,我们可以使用类似于上面最后一个示例的代码来生成第一个输出([JAVA-4, JAVA-3, JAVA-2, CPP-2, JAVA-1, CPP-1, C-1]
)。
它也是基于计数器的映射,但在这种情况下,我们设置每个文件名的出现次数,并在每次出现时减少计数器,而不是从0开始并增加计数器。
public static void main(String[] args) {
//List containing duplicate names
List<String> al = new ArrayList<String>(Arrays.asList("JAVA", "JAVA", "JAVA", "CPP", "JAVA", "CPP" ,"C"));
ArrayList<String> filenameList = new ArrayList<String>();
Map<String, Integer>counters = new HashMap<String, Integer>();
for(String fileName : al){
Integer count = counters.get(fileName);
boolean toConcat = true;
if(count == null){
//First occurrence.
//The number appended to the filename is the number of occurrences
count = Collections.frequency(al,fileName);
//Is it the only one? If so we won't append anything to the filename
//beware count is an Integer, not an int so '==' doesn't work
if(count.equals(1)){
toConcat = false;
}
} else {
//we can now decrease the counter
count -= 1;
}
counters.put(fileName, count);
if(toConcat){
filenameList.add(fileName.concat("-").concat("" + count));
//Why not filenameList.add(fileName + "-" + count)); ??
} else {
filenameList.add(fileName);
}
}
System.out.println(filenameList);
}
答案 1 :(得分:0)
集合中的最后一个元素有1个频率,您可以使用条件从最后删除它。
filenameList.add(fileName.concat(al.size() == 1?"":("-" + freq)));
答案 2 :(得分:0)
Roman C&s和Prerak Sola的答案很好,但它并不完全符合预期的输出。他们的输出将是。 。 。
[JAVA-4,JAVA-3,JAVA-2,CPP-2, JAVA , CPP ,C]
由于您要从源列表中删除,因此当您访问单个项目时,您无法确定该项目是否重复。您需要为每个项目保留某种地图或状态。
我会做以下事情。 。 。 (如果你真的真的想要有物品&#34; JAVA-1&#34; /&#34; CPP-1&#34;)
1)制作地图Map<String,Integer>
2)使用键作为列表项填充地图(例如&#34; JAVA&#34;,&#34; CPP&#34;)和值是列表项的计数(例如4&#34; JAVA& #34;,2为&#34; CPP&#34;)。
3)遍历条目。如果值== 1,则将密钥添加到输出列表中。如果计数&gt; 1,然后将ITEM + "-" + i
i = 1...count
添加到输出列表
这里有一些伪代码
List<String> output = new ArrayList<String>();
List<String> list = {"JAVA","JAVA","JAVA","CPP","JAVA","CPP", "C"};
Map<String, Integer> map = new HashMap<String, Integer>();
for(String item : list) {
if(map.contains(item)) {
map.put(item, map.get(item)+1);
} else {
map.put(item, 1);
}
}
for(Entry<String,Integer> entry : map.entrySet()) {
if(entry.value == 1) {
output.add(entry.key);
} else if(entry.value > 1) {
for(int i = 1; i <= entry.value; i++) {
output.add(entry.key + "-" + i);
}
}
}
注意 - 这应输出正确的项目,但不会保留订单
答案 3 :(得分:0)
如果你想降低从多项式到线性的时间复杂度,可以使用 HashMap
:
public static void main(String [] args){&#xA;&#xA; //包含重复名称的列表&#xA;列表与LT;字符串&GT; al = new ArrayList&lt; String&gt;(Arrays.asList(“JAVA”,“JAVA”,“JAVA”,“CPP”,“JAVA”,“CPP”,“C”));&#xA;的ArrayList&LT;字符串&GT; filenameList = new ArrayList&lt;&gt;();&#xA; Map&lt; String,Integer&gt; map = new HashMap&lt; String,Integer&gt;();&#xA;&#xA; while(!al.isEmpty()){&#xA; String fileName = al.remove(al.size() - 1);&#xA;整数计数= map.get(fileName);&#xA; if(count == null&amp;&amp; Collections.frequency(al,fileName)&gt; 0){&#xA; map.put(fileName,1);&#xA; fileName = addSequence(fileName,1);&#xA; }&#XA; if(count!= null){&#xA;计数++;&#XA; map.put(fileName,count);&#xA; fileName = addSequence(fileName,count);&#xA; }&#XA; filenameList.add(0,fileName);&#xA; }&#XA; System.out.println(filenameList);&#xA;}&#xA;&#xA; protected static String addSequence(String fileName,int freq){&#xA; return fileName.concat(“ - ”)。concat(“”+ freq);&#xA;}&#xA;
&#xA;&#xA; 及其输出: &#xA; [JAVA-4,JAVA-3,JAVA-2,CPP-2,JAVA-1,CPP-1,C]
答案 4 :(得分:0)
以下是我使用Java 8中的流程提出的建议。
代码示例:
public static void main(String[] args) throws Exception {
// List containing duplicate names
List<String> al = new ArrayList(Arrays
.asList("JAVA", "JAVA", "JAVA", "CPP", "JAVA", "CPP", "C"));
// Group items together that have a frequency greater than 1
Map<String, Long> groupings = al
.stream()
.collect(Collectors
.groupingBy(Object::toString, Collectors.counting()))
.entrySet()
.stream()
.filter(item -> item.getValue() > 1)
.collect(Collectors
.toMap(item -> item.getKey(), item -> item.getValue()));
// Apply reverse sequence to duplicate items
for (int i = 0; i < al.size(); i++) {
String item = al.get(i);
Long count = groupings.get(item);
if (count != null) {
al.set(i, item.concat("-" + count));
groupings.put(item, count - 1);
}
}
// Display results
System.out.println(al);
}
结果:
[JAVA-4, JAVA-3, JAVA-2, CPP-2, JAVA-1, CPP-1, C]
答案 5 :(得分:0)
在每次迭代中使用abc.GetValue( SecondParam);
都不会为您提供真正有效的算法。更好的方法是计算每个元素在字符串序列中出现的频率,然后分配数字。示例算法可能如下所示:
Collections.frequency
输出:
public static void main(String[] args) {
//List containing duplicate names
List<String> al = new ArrayList<String>(Arrays.asList("JAVA", "JAVA", "JAVA", "CPP", "JAVA", "CPP", "C"));
ArrayList<String> filenameList = new ArrayList<String>();
Map<String, Integer> counts = new HashMap<String, Integer>();
for(String element: al) {
if(counts.containsKey(element)) {
counts.put(element, counts.get(element) + 1);
} else {
counts.put(element, 1);
}
}
// remove all elements which have a count of 1
for(Iterator<Map.Entry<String, Integer>> it = counts.entrySet().iterator(); it.hasNext(); ) {
Map.Entry<String, Integer> entry = it.next();
if(entry.getValue() == 1) {
it.remove();
}
}
for(String element: al) {
if(counts.containsKey(element)) {
int counter = counts.get(element);
counts.put(element, counter - 1);
filenameList.add(element.concat("-").concat("" + counter));
} else {
filenameList.add(element);
}
}
System.out.println(filenameList);
}
答案 6 :(得分:0)
使用一些Java8功能的另一个解决方案(主要是因为我想尝试一些东西,它们并不是必需的)。它基本上就是你的方法,但是从原始列表中增加了一个字数统计图,以检查是否曾经多次出现过这个词。
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
public class FileNameSeq {
public static void main(String[] args) {
// List containing duplicate names
List<String> al = new ArrayList<>(Arrays.asList("JAVA", "JAVA", "JAVA", "CPP",
"JAVA", "CPP", "C"));
List<String> filenameList = new ArrayList<>();
Map<String, Long> wordCounts = al.stream().collect(
Collectors.groupingBy(Object::toString, Collectors.counting()));
Iterator<String> it = al.iterator();
while (it.hasNext()) {
String fileName = it.next();
if (wordCounts.get(fileName) > 1) {
fileName = fileName.concat("-" + Collections.frequency(al, fileName));
}
filenameList.add(fileName);
it.remove();
}
System.out.println(filenameList);
}
}
输出:
[JAVA-4, JAVA-3, JAVA-2, CPP-2, JAVA-1, CPP-1, C]
答案 7 :(得分:0)
public class SortingAndAddingData {
public static void main(String[] args) {
mapEffiecientWay();
}
private static void mapEffiecientWay() {
List<EmpFile> listEmp = prepareList();
// Yu can omit it if you dont want sorting.
Set<EmpFile> sortedEmpFile = new TreeSet<>((o1, o2) -> o2.getFileId().compareTo(o1.getFileId()));
Map<String, List<EmpFile>> mapDuplicate = new HashMap<>();
List<EmpFile> finalEmpFile = new ArrayList<>();
sortedEmpFile.addAll(listEmp);
sortedEmpFile.stream().forEach(file -> {
List<EmpFile> fileNameList = new ArrayList<>();
if (null != file.getFileName()) {
String combinedNameForDuplicate = file.getFileName();
if (null != mapDuplicate.get(combinedNameForDuplicate)) {
fileNameList = mapDuplicate.get(combinedNameForDuplicate);
file.setDuplicate(fileNameList.size());
}
fileNameList.add(file);
mapDuplicate.put(combinedNameForDuplicate, fileNameList);
} else {
finalEmpFile.add(file);
}
});
mapDuplicate.values().stream().forEach(finalEmpFile::addAll);
}
private static List<EmpFile> prepareList() {
EmpFile e1 = new EmpFile(); e1.setFileId("A"); e1.setFileName("A-1");
EmpFile e2 = new EmpFile(); e2.setFileId("B"); e2.setFileName("A-1");
EmpFile e3 = new EmpFile(); e3.setFileId("C"); e3.setFileName("A-2");
EmpFile e4 = new EmpFile(); e4.setFileId("D"); e4.setFileName("A-1");
List<EmpFile> listEmp = new ArrayList<>();
listEmp.add(e4); listEmp.add(e2); listEmp.add(e1); listEmp.add(e3);
return listEmp;
}
}
class EmpFile {
private String fileId; private String fileName; private int duplicate;
// Setters and getters
}
答案 8 :(得分:-2)
像这样制作for
循环:
for (int i = 0; al.size() > 0;) {
int freq = Collections.frequency(al, al.get(i));
String fileName = al.get(i);
if(freq != 1)
filenameList.add(fileName.concat("-").concat("" + freq));
else
filenameList.add(fileName);
al.remove(i); /* removing the element */
}