40

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

各行の最初の 2 つの値は、データを含む文字列で、1 つの要素に格納されます。

私がしたいのは、文字列データ要素を比較して削除することです。たとえば、2 番目の要素とその行で参照されているすべての要素を削除します。

今のところ、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  
            }
        }
    }
}
4

14 に答える 14

74

.contains()新しい要素を追加する前に、ArrayListのメソッドで重複をチェックしてみてください。

それはこのように見えるでしょう

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

これにより、リスト内の重複を防ぎ、人々が探しているように要素の順序を台無しにしないようにする必要があります.

于 2014-06-05T12:39:19.487 に答える
46

一意の値の配列リストを作成する

メソッドを使用できますSet.toArray()

重複する要素を含まないコレクション。より正式には、セットには、e1.equals(e2) のような要素 e1 と e2 のペアが含まれず、最大でも 1 つの null 要素が含まれます。その名前が示すように、このインターフェイスは数学的集合の抽象化をモデル化します。

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

于 2013-07-09T11:44:46.170 に答える
4

使用するSet

      ...
      Set<String> list = new HashSet<>();
      while (s.hasNext()){
         list.add(s.next());
      }
      ...
于 2013-07-09T11:50:22.953 に答える
3

で簡単にこれを行うことができますHashmap。明らかに、キー (文字列データ) といくつかの値があります。

すべての行をループして、マップに追加します。

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

この場合、最後に発生した重複行が保持されることに注意してください。最初に出現したものを保持して他を削除したい場合Map.containsKey(String stringData);は、マップに配置する前に でチェックを追加できます。

于 2013-07-09T11:46:10.893 に答える
2

カスタム オブジェクトの boolean equals() メソッドをオーバーライドするだけです。カスタム フィールド f1、f2、... オーバーライドを持つ 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() メソッドを使用して確認します。それでおしまい。

于 2015-01-22T09:49:17.683 に答える
2

解決策 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>>(のドキュメントを参照LinkedHashMapArrayList<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線形であるため、些細な場合を除いてその解決策を拒否する必要があります)、順序付けの欠如 (すべてを a に直接格納することHashSetは役に立ちません)、ArrayList操作の欠如 (LinkedHashSetそれ以外の場合は最善の解決策ですが、にインデックスを付けることができないため、ArrayList) の真の代替にはなりません。

a のHashMap<E, index>代わりに aを使用すると、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、高速なルックアップと の一意性プロパティが得られますHashMapHashMapには、 内のインデックスの場所にマップされた一意の値が含まれています。これによりArrayList、順序が強制され、反復が提供されます。

HashSetこのアプローチは、ソリューション #1で を使用する際のスケーラビリティの問題を解決します。このアプローチは、ファイルをすばやく読み取るには問題なく機能しますが、抽象化がなければ、すべての整合性操作を手動で処理し、複数の関数にまたがって時間の経過とともにそのコントラクトを強制する必要がある場合、複数の生データ構造を渡す必要があります。

と同様に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);

        for (Map.Entry<K, Integer> entry : map.entrySet()) {
            if (entry.getValue() == i) {
                map.remove(entry.getKey());
                break;
            }
        }

        decrementMapIndices(i);
        return v;
    }

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

        return null;
    }

    private void decrementMapIndices(int start) {
        for (Map.Entry<K, Integer> entry : map.entrySet()) {
            int i = entry.getValue();

            if (i > start) {
                map.put(entry.getKey(), i - 1);
            }
        }
    }

    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));
        }
    }
}
于 2019-09-22T23:27:31.260 に答える
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++;
        }
于 2013-07-09T11:57:02.267 に答える
0

一意の値が必要な場合は、SETインターフェイスの実装を使用する必要があります

于 2013-07-09T11:46:04.560 に答える
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);
    }
}
于 2019-01-28T16:01:43.180 に答える