2015-04-13 6 views
2

У меня есть ArrayList of Dico, и я пытаюсь извлечь четкую строку из Arraylist of Dico.Более быстрый метод для извлечения отдельной строки из Arraylist

Это класс Дико.

public class Dico implements Comparable { 
private final String m_term; 
private double m_weight; 
private final int m_Id_doc; 

public Dico(int Id_Doc, String Term, double tf_ief) { 
    this.m_Id_doc = Id_Doc; 
    this.m_term = Term; 
    this.m_weight = tf_ief; 
} 

public String getTerm() { 
    return this.m_term; 
} 

public double getWeight() { 
    return this.m_weight; 
} 

public void setWeight(double weight) { 
    this.m_weight = weight; 
} 

public int getDocId() { 
    return this.m_Id_doc; 
} 
} 

Я использую эту функцию, чтобы извлечь 1000 определенное значение с середины этого массива: я начать формировать середину и я принимать только определенное значение в обоих направлениях влево и вправо

public static List <String> get_sinificativ_term(List<Dico> dico) 
{ 
    List <String> term = new ArrayList(); 
    int pos_median= (dico.size()/2); 
    int count=0; 
    int i=0; 
    int j=0; 
    String temp_d = dico.get(pos_median).getTerm(); 
    String temp_g =temp_d; 
    term.add(temp_d); 

while(count < 999) // count of element 
    { 
    if(!temp_d.equals(dico.get((pos_median + i)).getTerm())) 

{  
    temp_d = dico.get((pos_median + i)).getTerm(); // save current term in temp 
    // System.out.println(temp_d); 
     term.add(temp_d); // add term to list        
     i++;  // go to the next value-->right 
     count++; 
    // System.out.println(temp_d); 
    } 

    else 
     i++; // go to the next value-->right 

    if(!temp_g.equals(dico.get((pos_median+j)).getTerm())) 

{  
     temp_g = dico.get((pos_median+j)).getTerm(); 

     term.add(temp_g);// add term to array 
    // System.out.println(temp_g); 
     j--; // go to the next value-->left 

     count++; 
    } 
    else 
     j--;// go to the next value-->left 

}  
    return term; 
} 

Я хотел бы сделать мое решение быстрее, чем эта функция, если это возможно, я могу сделать это с помощью Java SE 8 Streams?

+0

Замечание по качеству кода: рассмотрите использование разных имен переменных для i и j. Такие одиночные имена символов подходят для счетчиков for-loop; но я думаю, что в вашем примере они имеют совсем другое применение. Лучше дайте им имя, которое представляет, что они на самом деле, например indexLeftOfMedian для i, например ... – GhostCat

+0

Какова цель получения только 1000, и почему вы начинаете в центре? Кроме того, я предполагаю, что вы ожидаете дублирования getTerm() в разных элементах массива? – slambeth

+0

Ваш код выберет 999 или 1000 элементов. Ваш код разбивается, если не существует не менее 999 различных значений. Он также не работает, если список не отсортирован. Вы не сказали, что это так. Вы знаете, как большой «срок» должен быть таким, чтобы вы могли сделать его достаточно большим. Насколько быстрее это получится? Вы всегда должны перебирать, сравнивать и собирать. Вы можете избежать повторных вызовов типа 'dico.get ((pos_median + i)) .getTerm()' и сделать вашу жизнь проще, используя '.listIterator (pos_median)'. – zeroflagL

ответ

0

Вы не можете сделать что-то подобное?

public static List <String> get_sinificativ_term(List<Dico> dico) { 
    List<String> list = dico.stream() 
          .map(Dico::getTerm) 
          .distinct() 
          .limit(1000) 
          .collect(Collectors.toList()); 
    if(list.size() != 1000) { 
     throw new IllegalStateException("Need at least 1000 distinct values"); 
    } 
    return list; 
} 

Вам необходимо проверить размер, так как вы можете иметь менее 1000 различных значений. Если эффективность является проблемой, вы можете попытаться параллельно запустить конвейер и измерить, если он будет быстрее.

+0

Мне нужно 1000 отличных значений из центра распределения «медиана», потому что термины в Arraylist сортируются по весу [медиан-500, медиана + 500] находятся в центре статистического ditirbution срока в документе – tommy

1

Потоки не будут работать быстрее, но могут сделать его намного проще и понятнее.

Вот простейшая версия. Он будет принимать все индексы списка, сортировать их по расстоянию до середины списка, получать соответствующий термин, отфильтровывать дубликаты и ограничивать до 1000 элементов. Это, безусловно, будет медленнее, чем ваш итеративный код, но гораздо легче следовать, потому что код аккуратно отражает его описание на английском языке:

public static List<String> get_sinificativ_term(List<Dico> dicolist) { 
    int size = dicolist.size(); 

    return IntStream.range(0, size) 
      .boxed() 
      .sorted(comparing(i -> Math.abs(size/2 - i))) 
      .map(dicolist::get) 
      .map(Dico::getTerm) 
      .distinct() 
      .limit(1000) 
      .collect(toList()); 
} 

Если список действительно огромен, и вы хотите, чтобы избежать сортировок, вы можете торговать от некоторых простота в производительности. Эта версия немного математична, чтобы идти вправо-влево-вправо-влево от центра:

public static List<String> get_sinificativ_term(List<Dico> dicolist) { 
    int size = dicolist.size(); 

    return IntStream.range(0, size) 
      .map(i -> i % 2 == 0 ? (size + i)/2 : (size - i - 1)/2) 
      .mapToObj(i -> dicolist.get(i).getTerm()) 
      .distinct() 
      .limit(1000) 
      .collect(toList()); 
} 
+0

, прежде всего спасибо вам за помощь. вы забыли это 'collect (Collectors.toList());' – tommy

+0

Может быть менее интуитивно понятным для чтения, но '.map (i -> size + (i^i <<31>> 31) >> 1)' является потенциально более эффективным альтернатива '.map (i -> i% 2 == 0? (размер + i)/2: (размер - i - 1)/2) – Holger