【问题标题】:Faster method to extract distinct string from an Arraylist从 Arraylist 中提取不同字符串的更快方法
【发布时间】:2015-04-13 13:42:24
【问题描述】:

我有一个 Dico 的 ArrayList,我尝试从 Dico 的 Arraylist 中提取一个不同的字符串。

这是 Dico 类。

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 做这个吗?

【问题讨论】:

  • 关于代码质量的旁注:考虑为 i 和 j 使用不同的变量名。这样的单字符名称对于 for 循环计数器是可以的;但我认为在您的示例中,它们的用法有很大不同。最好给他们一个代表他们实际情况的名称,例如 indexLeftOfMedian for i ...
  • 只得到1000的目的是什么,为什么要从中心开始?另外,我假设您期望 getTerm() 在不同的数组元素中存在重复项?
  • 您的代码将提取 999 或 1000 个元素。如果没有至少 999 个不同的值,您的代码就会中断。如果列表未排序,它也不起作用。你没有说它是。你知道term 应该有多大,所以你可以一开始就让它足够大。它应该快多少?你总是需要迭代、比较和收集。您可以避免像dico.get(( pos_median + i) ).getTerm() 这样的重复呼叫,并使用.listIterator(pos_median) 让您的生活更轻松。
  • @zeroflagL 好的,感谢您提供此信息。

标签: java string arraylist java-8 distinct-values


【解决方案1】:

Streams 不会让它更快,但可以让它更简单、更清晰。

这是最简单的版本。它将获取所有列表索引,按到列表中间的距离对它们进行排序,获取相应的术语,过滤掉重复项并限制为 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());
}

【讨论】:

  • 首先感谢您的帮助。你忘了这个collect(Collectors.toList());
  • 阅读起来可能不太直观,但.map(i -&gt; size+(i^i&lt;&lt;31&gt;&gt;31)&gt;&gt;1) 可能是.map(i -&gt; i % 2 == 0 ? (size + i) / 2 : (size - i - 1) / 2) 更有效的替代方案
【解决方案2】:

你不能这样做吗?

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 个不同的值。如果效率是一个问题,您可以尝试并行运行管道并测量它是否更快。

【讨论】:

  • 我需要来自分布中心“中位数”的 1000 个不同值,因为 Arraylist 中的术语按权重排序 [median-500,median+500] 位于文档中术语统计分布的中心
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多