创建一个独特值的Arraylist

时间:2013-07-09 11:41:58

标签: java arraylist

我在Java中有一个带有这些值的arraylist(很多行,这只是一个提取)

  

20/03/2013 23:31:46 6870 6810 6800 6720 6860 6670 6700 6650 6750 6830 34864 34272   20/03/2013 23:31:46 6910 6780 6800 6720 6860 6680 6620 6690 6760 6790 35072 34496

前两个值是包含数据并存储在单个元素中的字符串。

我想要做的是比较字符串数据元素并删除例如第二个和引用该行的所有元素。

现在,我使用了一个for循环,每13个元素比较字符串(为了只比较数据字符串)

我的问题:我可以实施其他更好的解决方案吗?

这是我的代码:

import java.util.Scanner;
import java.util.List;
import java.util.ArrayList;
import java.io.*;
import java.text.SimpleDateFormat;
import java.util.Date;

public class Downsampler {
    public static void main(String[] args) throws Exception{

    //The input file
    Scanner s = new Scanner(new File("prova.txt"));


    //Saving each element of the input file in an arraylist 
    ArrayList<String> list = new ArrayList<String>();
    while (s.hasNext()){
        list.add(s.next());
    }
    s.close();

    //Arraylist to save modified values
    ArrayList<String> ds = new ArrayList<String>();

    //
    int i;
    for(i=0; i<=list.size()-13; i=i+14){

            //combining the first to values to obtain data  
            String str = list.get(i)+" "+list.get(i+1);
            ds.add(str);
            //add all the other values to arraylist ds
            int j;
            for(j=2; j<14; j++){
                ds.add(list.get(i+j));
            }

            //comparing data values
            int k;  
            for(k=0; k<=ds.size()-12; k=k+13){
                ds.get(k); //first data string element  
                //Comparing with other strings and delete
                //TODO  
            }
    }
    }
}

14 个答案:

答案 0 :(得分:57)

在添加新元素之前,尝试使用ArrayList上的.contains()方法检查重复项。

它看起来像这样

   if(!list.contains(data))
       list.add(data);

这应该防止列表中的重复,以及不会弄乱元素的顺序,就像人们似乎在寻找。

答案 1 :(得分:39)

  

创建唯一值的Arraylist

您可以使用Set.toArray()方法。

  

不包含重复元素的集合。更正式的,集合   不包含元素e1和e2对,使得e1.equals(e2)和at   大多数一个null元素。正如其名称所暗示的,这个界面模型   数学集抽象。

http://docs.oracle.com/javase/6/docs/api/java/util/Set.html

答案 2 :(得分:14)

HashSet hs = new HashSet();
                hs.addAll(arrayList);
                arrayList.clear();
                arrayList.addAll(hs);

答案 3 :(得分:3)

你可以使用一套。这是一个不接受重复的集合。

答案 4 :(得分:3)

使用Set

      ...
      Set<String> list = new HashSet<>();
      while (s.hasNext()){
         list.add(s.next());
      }
      ...

答案 5 :(得分:3)

 //Saving each element of the input file in an arraylist 
    ArrayList<String> list = new ArrayList<String>();
    while (s.hasNext()){
        list.add(s.next());
    }

//That's all you need
list = (ArrayList) list.stream().distinct().collect(Collectors.toList());

答案 6 :(得分:2)

您可以使用Hashmap轻松完成此操作。你显然有一个键(这是字符串数据)和一些值。

循环播放所有线条并将其添加到地图中。

Map<String, List<Integer>> map = new HashMap<>();
...
while (s.hasNext()){
  String stringData = ...
  List<Integer> values = ...
  map.put(stringData,values);
}

请注意,在这种情况下,您将保持重复行的最后出现。如果您希望保留第一次出现并删除其他内容,则可以在放入地图之前添加Map.containsKey(String stringData);支票。

答案 7 :(得分:2)

晚会很晚,但这是我的两分钱

使用LinkedHashSet

我认为您需要的是一个收藏集:

  • 不允许您插入重复项;
  • 保留插入顺序。

LinkedHashSet执行此操作。与使用ArrayList相比,优点是LinkedHashSet的{​​{1}}操作的复杂度为 O(1),而不是contains,其中具有 O(n)


当然,您需要正确实现对象的ArrayListequals方法。

答案 8 :(得分:1)

只是覆盖自定义对象的布尔equals()方法。假设您有一个带有自定义字段f1,f2,... override

的ArrayList
@Override
public boolean equals(Object o) {
    if (this == o) return true;
    if (!(o instanceof CustomObject)) return false;

    CustomObject object = (CustomObject) o;

    if (!f1.equals(object.dob)) return false;
    if (!f2.equals(object.fullName)) return false;
    ...
    return true;
}

并使用ArrayList实例的contains()方法进行检查。就是这样。

答案 9 :(得分:0)

如果您需要唯一值,则应使用SET接口

的实现

答案 10 :(得分:0)

您可以从文件到地图进行读取,其中键是日期,如果日期已经在地图中则跳过整行

        Map<String, List<String>> map = new HashMap<String, List<String>>();

        int i = 0;
        String lastData = null;
        while (s.hasNext()) {
            String str = s.next();
            if (i % 13 == 0) {
                if (map.containsKey(str)) {
                    //skip the whole row
                    lastData = null;
                } else {
                    lastData = str;
                    map.put(lastData, new ArrayList<String>());
                }
            } else if (lastData != null) {
                map.get(lastData).add(str);
            }


            i++;
        }

答案 11 :(得分:0)

我使用助手类。不知道是好是坏

public class ListHelper<T> {
    private final T[] t;

    public ListHelper(T[] t) {
        this.t = t;
    }

    public List<T> unique(List<T> list) {
       Set<T> set = new HashSet<>(list);
        return Arrays.asList(set.toArray(t));
    }
}

使用和测试:

import static org.assertj.core.api.Assertions.assertThat;


public class ListHelperTest {

    @Test
    public void unique() {
        List<String> s = Arrays.asList("abc", "cde", "dfg", "abc");
        List<String> unique = new ListHelper<>(new String[0]).unique(s);
        assertThat(unique).hasSize(3);
    }
}

或Java8版本:

public class ListHelper<T> {
    public Function<List<T>, List<T>> unique() {
        return l -> l.stream().distinct().collect(Collectors.toList());
    }
}

public class ListHelperTest {
    @Test
    public void unique() {
        List<String> s = Arrays.asList("abc", "cde", "dfg", "abc");
        assertThat(new ListHelper<String>().unique().apply(s)).hasSize(3);
    }
}

答案 12 :(得分:0)

解决方案1:HashSet

对于将文件读入具有唯一性约束的ArrayList的眼前问题的一个好的解决方案是仅保留HashSet个可见项。在处理一行之前,我们检查其键是否尚未在集合中。如果不是,我们将键添加到集合中以将其标记为完成,然后将行数据添加到结果ArrayList中。

import java.util.*;
import java.io.*;

public class Main {
    public static void main(String[] args) 
        throws FileNotFoundException, IOException {

        String file = "prova.txt";
        ArrayList<String[]> data = new ArrayList<>();
        HashSet<String> seen = new HashSet<>();

        try (BufferedReader br = new BufferedReader(new FileReader(file))) {
            for (String line; (line = br.readLine()) != null;) {
                String[] split = line.split("\\s+");
                String key = split[0] + " " + split[1];

                if (!seen.contains(key)) {
                    data.add(Arrays.copyOfRange(split, 2, split.length));
                    seen.add(key);
                }
            }
        }

        for (String[] row : data) {
            System.out.println(Arrays.toString(row));
        }
    }
}

解决方案2:LinkedHashMap / LinkedHashSet

由于我们在此特定数据集中具有键值对,因此我们可以将所有内容滚动到LinkedHashMap<String, ArrayList<String>>see docs for LinkedHashMap)中,这样可以保留顺序,但不能将其编入索引(用例驱动的决策,但与上述策略相同。ArrayList<String>String[]在这里是任意的-它可以是任何数据值)。请注意,此版本使保存最近看到的密钥而不是最旧的密钥变得容易(删除!data.containsKey(key)测试)。

import java.util.*;
import java.io.*;

public class Main {
    public static void main(String[] args) 
        throws FileNotFoundException, IOException {

        String file = "prova.txt";
        LinkedHashMap<String, ArrayList<String>> data = new LinkedHashMap<>();

        try (BufferedReader br = new BufferedReader(new FileReader(file))) {
            for (String line; (line = br.readLine()) != null;) {
                String[] split = line.split("\\s+");
                String key = split[0] + " " + split[1];

                if (!data.containsKey(key)) {
                    ArrayList<String> val = new ArrayList<>();
                    String[] sub = Arrays.copyOfRange(split, 2, split.length); 
                    Collections.addAll(val, sub);
                    data.put(key, val);
                }
            }
        }

        for (Map.Entry<String, ArrayList<String>> e : data.entrySet()) {
            System.out.println(e.getKey() + " => " + e.getValue());
        }
    }
}

解决方案3:ArrayListSet

以上示例代表了非常狭窄的用例。这是一个通用ArrayListSet类的草图,该类在保留唯一性的同时保持了常规的列表行为(add / set / remove等)。

基本上,该类是本文中解决方案#1的抽象(HashSetArrayList组合),但风格略有不同(数据本身用于确定唯一性,而不是键,但这是一个更真实的“ ArrayList”结构)。

此类解决了效率问题(ArrayList#contains是线性的,因此,除琐碎的情况外,我们应拒绝该解决方案),缺乏排序(将所有内容直接存储在HashSet中)无济于事),缺少ArrayList操作(否则LinkedHashSet是最好的解决方案,但我们无法对其进行索引,因此它并不是ArrayList的真正替代)。

使用HashMap<E, index>代替HashSet可以加快remove(Object o)indexOf(Object o)的功能(但会降低sort的速度)。线性remove(Object o)是普通HashSet的主要缺点。

import java.util.*;

public class ArrayListSet<E> implements Iterable<E>, Set<E> {
    private ArrayList<E> list;
    private HashSet<E> set;

    public ArrayListSet() {
        list = new ArrayList<>();
        set = new HashSet<>();
    }

    public boolean add(E e) {
        return set.add(e) && list.add(e);
    }

    public boolean add(int i, E e) {
        if (!set.add(e)) return false;
        list.add(i, e);
        return true;
    }

    public void clear() {
        list.clear();
        set.clear();
    }

    public boolean contains(Object o) {
        return set.contains(o);
    }

    public E get(int i) {
        return list.get(i);
    }

    public boolean isEmpty() {
        return list.isEmpty();
    }

    public E remove(int i) {        
        E e = list.remove(i);
        set.remove(e);
        return e;
    }

    public boolean remove(Object o) {        
        if (set.remove(o)) {
            list.remove(o);
            return true;
        }

        return false;
    }

    public boolean set(int i, E e) {
        if (set.contains(e)) return false;

        set.add(e);
        set.remove(list.set(i, e));
        return true;
    }

    public int size() {
        return list.size();
    }

    public void sort(Comparator<? super E> c) {
        Collections.sort(list, c);
    }

    public Iterator<E> iterator() {
        return list.iterator();
    }

    public boolean addAll(Collection<? extends E> c) {
        int before = size();
        for (E e : c) add(e);
        return size() == before;
    }

    public boolean containsAll(Collection<?> c) {
        return set.containsAll(c);
    }

    public boolean removeAll(Collection<?> c) {
        return set.removeAll(c) && list.removeAll(c);
    }

    public boolean retainAll(Collection<?> c) {
         return set.retainAll(c) && list.retainAll(c);
    }

    public Object[] toArray() {
        return list.toArray();
    }

    public <T> T[] toArray(T[] a) {
        return list.toArray(a);
    }
}

用法示例:

public class ArrayListSetDriver {
    public static void main(String[] args) {
        ArrayListSet<String> fruit = new ArrayListSet<>();
        fruit.add("apple");
        fruit.add("banana");
        fruit.add("kiwi");
        fruit.add("strawberry");
        fruit.add("apple");
        fruit.add("strawberry");

        for (String item : fruit) {
            System.out.print(item + " "); // => apple banana kiwi strawberry
        }

        fruit.remove("kiwi");
        fruit.remove(1);
        fruit.add(0, "banana");
        fruit.set(2, "cranberry");
        fruit.set(0, "cranberry");
        System.out.println();

        for (int i = 0; i < fruit.size(); i++) {
            System.out.print(fruit.get(i) + " "); // => banana apple cranberry
        }

        System.out.println();
    }
}

解决方案4:ArrayListMap

此类解决了ArrayListSet的一个缺点,即我们要存储的数据及其关联的密钥可能不相同。此类提供了put方法,该方法在与存储在基础ArrayList中的数据不同的对象上实施唯一性。这正是我们需要解决的该线程中的原始问题。这为我们提供了ArrayList的排序和迭代,但为HashMap提供了快速的查找和唯一性。 HashMap包含映射到ArrayList中它们的索引位置的唯一值,这可以强制排序并提供迭代。

此方法解决了在解决方案#1中使用HashSet的可伸缩性问题。这种方法可以快速读取文件,但如果没有抽象,则需要手动处理所有一致性操作,并且如果需要在多个功能上随时间推移强制执行该约定,则必须传递多个原始数据结构。

ArrayListSet一样,这可以视为概念证明,而不是完整的实现。

import java.util.*;

public class ArrayListMap<K, V> implements Iterable<V>, Map<K, V> {
    private ArrayList<V> list;
    private HashMap<K, Integer> map;

    public ArrayListMap() {
        list = new ArrayList<>();
        map = new HashMap<>();
    }

    public void clear() {
        list.clear();
        map.clear();
    }

    public boolean containsKey(Object key) {
        return map.containsKey(key);
    }

    public boolean containsValue(Object value) {
        return list.contains(value);
    }

    public V get(int i) {
        return list.get(i);
    }

    public boolean isEmpty() {
        return map.isEmpty();
    }

    public V get(Object key) {
        return list.get(map.get(key));
    }

    public V put(K key, V value) {
        if (map.containsKey(key)) {
            int i = map.get(key);
            V v = list.get(i);
            list.set(i, value);
            return v;
        }

        list.add(value);
        map.put(key, list.size() - 1);
        return null;
    }

    public V putIfAbsent(K key, V value) {
        if (map.containsKey(key)) {
            if (list.get(map.get(key)) == null) {
                list.set(map.get(key), value);
                return null;
            }

            return list.get(map.get(key));
        }

        return put(key, value);
    }

    public V remove(int i) {
        V v = list.remove(i);
        map.values().remove(v);
        return v;
    }

    public V remove(Object key) {
        if (map.containsKey(key)) {
            int i = map.remove(key);
            V v = list.get(i);
            list.remove(i);
            return v;
        }

        return null;
    }

    public int size() {
        return list.size();
    }

    public void putAll(Map<? extends K, ? extends V> m) {
        for (Map.Entry<? extends K, ? extends V> entry : m.entrySet()) {
            put(entry.getKey(), entry.getValue());
        }
    }

    public Set<Map.Entry<K, V>> entrySet() {
        Set<Map.Entry<K, V>> es = new HashSet<>();

        for (Map.Entry<K, Integer> entry : map.entrySet()) {
            es.add(new AbstractMap.SimpleEntry<>(
                entry.getKey(), list.get(entry.getValue())
            ));
        }

        return es;
    }

    public Set<K> keySet() {
        return map.keySet();
    }

    public Collection<V> values() {
        return list;
    }

    public Iterator<V> iterator() {
        return list.iterator();
    }

    public Object[] toArray() {
        return list.toArray();
    }

    public <T> T[] toArray(T[] a) {
        return list.toArray(a);
    }
}

以下是针对原始问题的课程:

import java.io.*;

public class Main {
    public static void main(String[] args) 
        throws FileNotFoundException, IOException {

        String file = "prova.txt";
        ArrayListMap<String, String[]> data = new ArrayListMap<>();

        try (BufferedReader br = new BufferedReader(new FileReader(file))) {
            for (String line; (line = br.readLine()) != null;) {
                String[] split = line.split("\\s+");
                String key = split[0] + " " + split[1];
                String[] sub = Arrays.copyOfRange(split, 2, split.length); 
                data.putIfAbsent(key, sub); 
            }
        }

        for (Map.Entry<String, String[]> e : data.entrySet()) {
            System.out.println(e.getKey() + " => " + 
                java.util.Arrays.toString(e.getValue()));
        }

        for (String[] a : data) {
            System.out.println(java.util.Arrays.toString(a));
        }
    }
}

答案 13 :(得分:0)

如果要使用现有列表中的唯一值创建列表,则可以使用

List myUniqueList = myList.stream().distinct().collect(Collectors.toList());