如何将序列添加到列表中存储的名称(如果重复)

时间:2015-07-23 14:42:24

标签: java arraylist

给出以下代码:

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"

我需要做出哪些更改才能生成以后的输出?

9 个答案:

答案 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和Prera​​k 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

&#xA;&#xA;
  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]

&#xA;

答案 4 :(得分:0)

以下是我使用Java 8中的流程提出的建议。

  1. 将项目组合在一起,放入频率计数大于1的地图
  2. 将反向序列计数应用于地图中的项目
  3. 代码示例:

    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 */
}