Создать ArrayList уникальных значений
У меня есть 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 Main {
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
}
}
}
}
Ответы
Ответ 1
Создайте Arraylist уникальных значений
Вы можете использовать метод Set.toArray()
.
Коллекция, которая не содержит повторяющихся элементов. Более формально, наборы не содержат пары элементов e1 и e2 таких, что e1.равнения (e2) и at самый один нулевой элемент. Как видно из названия, эти интерфейсные модели математическая установка абстракции.
http://docs.oracle.com/javase/6/docs/api/java/util/Set.html
Ответ 2
Попробуйте проверить дубликаты с помощью метода .contains()
в ArrayList, прежде чем добавлять новый элемент.
Он будет выглядеть примерно так.
if(!list.contains(data))
list.add(data);
Это должно предотвратить дублирование в списке, а также не испортить порядок элементов, как будто люди ищут.
Ответ 3
HashSet hs = new HashSet();
hs.addAll(arrayList);
arrayList.clear();
arrayList.addAll(hs);
Ответ 4
//Saving each element of the input file in an arraylist
ArrayList<String> list = new ArrayList<String>();
while (s.hasNext()){
list.add(s.next());
}
//That all you need
list = (ArrayList) list.stream().distinct().collect(Collectors.toList());
Ответ 5
Вы можете использовать Set. Это коллекция, которая не принимает дубликаты.
Ответ 6
Используйте Set
...
Set<String> list = new HashSet<>();
while (s.hasNext()){
list.add(s.next());
}
...
Ответ 7
Довольно поздно на вечеринку, но вот мои два цента
Я предполагаю, что вам нужна коллекция, которая:
- запрещает вам вставлять дубликаты;
- сохраняет порядок вставки.
LinkedHashSet
делает это. Преимуществом по сравнению с использованием ArrayList
является то, что LinkedHashSet
имеет сложность O (1) для contains
операции, в отличие от ArrayList
, который имеет O (N).
Конечно, вам нужно правильно реализовать ваши методы equals
и hashCode
.
Ответ 8
Вы можете легко сделать это с помощью Hashmap
. У вас, очевидно, есть ключ (который является строковыми данными) и некоторые значения.
Прокрутите все ваши строки и добавьте их на свою карту.
Map<String, List<Integer>> map = new HashMap<>();
...
while (s.hasNext()){
String stringData = ...
List<Integer> values = ...
map.put(stringData,values);
}
Обратите внимание, что в этом случае вы сохраните последнее наличие повторяющихся строк. Если вы предпочитаете удерживать первый и удалять другие, вы можете добавить чек с помощью Map.containsKey(String stringData);
перед тем, как положить карту.
Ответ 9
Просто переопределить метод boolean equals() настраиваемого объекта. Скажем, у вас есть ArrayList с настраиваемым полем f1, f2,... override
@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(). Что это.
Ответ 10
Если вам нужны уникальные значения, вы должны использовать реализацию интерфейса SET
Ответ 11
Вы можете читать из файла на карту, где ключ - это дата и пропустить, если целая строка, если дата уже находится на карте
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++;
}
Ответ 12
Я использую вспомогательный класс. Не уверен, хорошо это или плохо
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);
}
}
Ответ 13
Решение № 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>>
(см. Документы по 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 в этом посте (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 String toString() {
StringBuilder sb = new StringBuilder();
sb.append("[");
for (int i = 0; i < list.size() - 1; i++) {
sb.append(list.get(i) + ", ");
}
if (!list.isEmpty()) {
sb.append(list.get(list.size() - 1));
}
sb.append("]");
return sb.toString();
}
}
Пример использования:
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();
}
}