for循环提高效率的方式

以前看到过一个文章说的这方面,具体的不记得所以来问问,大致是这样的:

1.在嵌套for循环中使用字典(hashtable?)而不是把所有的都遍历

2.当时我个人觉得有点类似:
from a in table1
from b in table2
对比:
fram a in table1
join b in table2 on ... 的效率对比

忘记具体怎么说的了,可能我没有表述清楚
希望能说一说在嵌套for循环中使用字典避免多次循环提高效率的方式

前言 写道
for/in循环就是JDK5.0中所谓的增强For循环,它能对数组和集合进行遍历,使用它会使用你的代码短小而精炼的多。这里将介绍以下内容:

传统的for循环和增强for循环的比较
定制自己的增强for循环
增强for循环的局限性

一:传统的for循环和增强for循环的比较

//传统的数组遍历
String[] persons={"张三","李四","王五"};
for(int i=0;i<persons.length;i++){
System.out.println(persons[i]);
}
//使用增强for循环的数组遍历
String[] persons={"张三","李四","王五"};
for(String person:persons){
System.out.println(person);

//传统的Iterator遍历集合
List persons=new ArrayList();
persons.add("张三");
persons.add("李四");
persons.add("王五");
for(Iterator i=persons.iterator();i.hasNext();){
String person=i.next();
System.out.println(person);
}
//使用增强For循环遍历集合
List persons=new ArrayList();
persons.add("张三");
persons.add("李四");
persons.add("王五");
for(String person:persons){
System.out.println(person);
}

可以看到使用增强for循环使得代码变得短小而精炼的多,如果你觉得这点变化还体现不出来,可以忍受,那你可以试试嵌套for循环,就会感觉到增强for循环的好处了,这里就不贴代码了。
二:定制自己的增强for循环
众所周知,增强for循环是按数组或者集合的内在顺序输出的,如果我们想在遍历的时候定制行为怎么做呢?下面就以一个逆序输出的例子说明怎么定制自己的增强for循环。
要想使用增强for循环,必须实现Iterable接口。

import java.util.Iterator;

/**

  • 一个简单的逆序输出增强for循环
  • @author * */ public class ReverIterableClass implements Iterable { protected T[] elements; public ReverIterableClass(T... elems) { this.elements=elems; //this.object=(T[])new Object[ts.length]; } public Iterator iterator() { return new Iterator(){ private int current=elements.length-1; public boolean hasNext() { return current>-1; }

public T next() {
return elements[current--];
}

public void remove() {
throw new UnsupportedOperationException("目前不支持删除操作");
}
};
}
public static void main(String[] args){
ReverIterableClass iterableClass=new ReverIterableClass("a","b","c","d");
for(String s:iterableClass){
System.out.println(s);
}
}

}
在这个程序里我们定制了自己的输出行为--逆序输出,当然你也可以定义属于你自己的,只需要在next()函数里写处理代码即可。
三:增强for循环的局限性
不能在增强for循环中访问位置,例如下面的代码:

String[] persons={"张三","李四","王五"};
for(int i=0;i<persons.length;i++){
System.out.println(i+":"+persons[i]);
}

在增强for循环中你是得不到这个位置"i"的。
例如还有我们常用的在组合sql语句,select字段的时候,当是最后一个字段时,不能加","的。
String[] fields={"name","age","sex"};
StringBuilder sql=new StringBuilder("select ");
for(int i=0;i<fields.length;i++){
if(i<fields.length-1){
sql.append(fields[i]+",");
}else{
sql.append(fields[i]);
}
}
sql.append(" from t_user");
System.out.println(sql);
这在增强for循环中也是不能处理的。。
还有对元素的删除,在增强for循环中也不能做到,但是使用传统的Iterator接口遍历时就可以使用他的remove()方法删除符合条件的元素。

foreach的语句格式:for(元素类型t 元素变量x : 遍历对象obj){ 引用了x的java语句;}下面通过两个例子简单例子看看foreach是如何简化编程的。代码如下:一、foreach简化数组和集合的遍历import java.util.Arrays;
import java.util.List;
import java.util.ArrayList;

public class TestArray {
public static void main(String args[]) {
TestArray test = new TestArray();
test.test1();
test.listToArray();
test.testArray3();

}

/**

  • foreach语句输出一维数组 */ public void test1() { //定义并初始化一个数组 int arr[] = {2, 3, 1}; System.out.println("----1----排序前的一维数组"); for (int x : arr) { System.out.println(x); //逐个输出数组元素的值 }

//对数组排序
Arrays.sort(arr);

//利用java新特性for each循环输出数组
System.out.println("----1----排序后的一维数组");
for (int x : arr) {
System.out.println(x); //逐个输出数组元素的值
}
}

/**

  • 集合转换为一维数组 */ public void listToArray() { //创建List并添加元素 List list = new ArrayList(); list.add("1"); list.add("3"); list.add("4");

//利用froeach语句输出集合元素
System.out.println("----2----froeach语句输出集合元素");
for (String x : list) {
System.out.println(x);
}

//将ArrayList转换为数组
Object s[] = list.toArray();

//利用froeach语句输出集合元素
System.out.println("----2----froeach语句输出集合转换而来的数组元素");
for (Object x : s) {
System.out.println(x.toString()); //逐个输出数组元素的值
}
}

/**

  • foreach输出二维数组测试 */ public void testArray2() { int arr2[][] = {{4, 3}, {1, 2}}; System.out.println("----3----foreach输出二维数组测试"); for (int x[] : arr2) { for (int e : x) { System.out.println(e); //逐个输出数组元素的值 } } }

/**

  • foreach输出三维数组 */ public void testArray3() { int arr[][][] = { {{1, 2}, {3, 4}}, {{5, 6}, {7, 8}} };

System.out.println("----4----foreach输出三维数组测试");
for (int[][] a2 : arr) {
for (int[] a1 : a2) {
for (int x : a1) {
System.out.println(x);
}
}
}
}
}运行结果:----1----排序前的一维数组
2
3
1
----1----排序后的一维数组
1
2
3
----2----froeach语句输出集合元素
1
3
4
----2----froeach语句输出集合转换而来的数组元素
1
3
4
----4----foreach输出三维数组测试
1
2
3
4
5
6
7
8

Process finished with exit code 0

二、foreach语句的局限性通过上面的例子可以发现,如果要引用数组或者集合的索引,则foreach语句无法做到,foreach仅仅老老实实地遍历数组或者集合一遍。下面看一个例子就明白了:/**
public class TestArray2 {

public static void main(String args[]) {
//定义一个一维数组
int arr[] = new int[4];
System.out.println("----未赋值前输出刚刚定义的数组----");
for (int x : arr) {
System.out.println(x);
}

//通过索引给数组元素赋值
System.out.println("----通过循环变量给数组元素赋值----");
for (int i = 3; i > 0; i--) {
arr[i] = i;
}
//循环输出创建的数组
System.out.println("----赋值后,foreach输出创建好的数组----");
for (int x : arr) {
System.out.println(x);
}
}
}
运行结果:----未赋值前输出刚刚定义的数组----
0
0
0
0
----通过循环变量给数组元素赋值----
----赋值后,foreach输出创建好的数组----
0
1
2
3

Process finished with exit code 0

四:小结
增强for循环有它的好处,比如简洁,代码优雅,如果能使用增强for循环,一定要优先使用。

字典是hashtable的,根据key值获取值,很快

from a in table1
from b in table2
对比:
fram a in table1
join b in table2 on ... 的效率对比

前者相当于两重循环,算法复杂度N^2,后者是分别遍历一次a b,求出key,装入类似字典的结构,然后直接匹配,算法复杂度是logN
后者效率高很多

 用hashtable/dictionary是因为两个表不是有序的。
如果是有序的,也可以这么写
var itl1 = table1.GetEnumerator();
var itl2 = table1.GetEnumerator();
bool b1 = itl2.MoveNext();
bool b2 = itl2.MoveNext();
while (!b1 && !b2)
{
    if (itl1.Current.CompareTo(itl2.Current) > 0 && b2) {b2 = itl2.MoveNext(); continue;}
        if (itl1.Current.CompareTo(itl2.Current) < 0 && b2) {b1 = itl1.MoveNext(); cuntinue;}
        //itl1.Current和itl2.Current相等,匹配成功
        ...
}
代替(如下代码功能类似但是效率低)
foreach (var i1 in table1)
    foreach (var i2 in table2)
        {
            if (i1 == i2) // 匹配成功
        }

from a in table1
from b in table2
对比:
fram a in table1
join b in table2 on

后者的效率比前者同

from a
from b
调用的是
SelectMany这个Linq操作
google 笛卡尔集