我在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
}
}
}
}
答案 0 :(得分:57)
在添加新元素之前,尝试使用ArrayList上的.contains()
方法检查重复项。
它看起来像这样
if(!list.contains(data))
list.add(data);
这应该防止列表中的重复,以及不会弄乱元素的顺序,就像人们似乎在寻找。
答案 1 :(得分:39)
创建唯一值的Arraylist
您可以使用Set.toArray()
方法。
不包含重复元素的集合。更正式的,集合 不包含元素e1和e2对,使得e1.equals(e2)和at 大多数一个null元素。正如其名称所暗示的,这个界面模型 数学集抽象。
答案 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)。
当然,您需要正确实现对象的ArrayList
和equals
方法。
答案 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)
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));
}
}
}
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());
}
}
}
ArrayListSet
以上示例代表了非常狭窄的用例。这是一个通用ArrayListSet
类的草图,该类在保留唯一性的同时保持了常规的列表行为(add
/ set
/ remove
等)。
基本上,该类是本文中解决方案#1的抽象(HashSet
与ArrayList
组合),但风格略有不同(数据本身用于确定唯一性,而不是键,但这是一个更真实的“ 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();
}
}
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());