Java 再会迭代器模式

GOF定义

迭代器模式(别名: 游标)
提供一种方法顺序访问一个聚合对象中的各个元素, 而又不需要暴露该对象的内部表示

概述

链表和散列表等数据结构都可以存放若干个对象的集合, 其区别是按着不同的方式来存储对象. 我们希望无论何种集合, 应当允许程序以一种统一的方式遍历集合中的对象, 而不需要知道这些对象在集合中是如何表示存储的.
迭代器模式是遍历集合的成熟模式, 迭代器模式的关键是将遍历集合的任务交给一个称作迭代器的对象.

迭代器模式的优点和适合使用迭代器模式的情景

优点

  1. 用户使用迭代器访问集合中的对象, 而不需要知道这些对象在集合中是如何表示及存储的.
  2. 用户可以同时使用多个迭代器遍历一个集合.

适合使用观察者模式的情景

  1. 让用户访问一个集合中的对象, 但是不想暴露对象在集合中的存储结构
  2. 希望对遍历不同的集合提供一个统一的接口

模式的结果与使用

四种角色

集合(Aggregate)

这里使用 java.util 包中的 Collection 接口作为模式中的集合对象. Java 所有的集合都实现了该接口.

具体集合(ConcreteAggregate)

这里使用 java.util 包中的 HashSet 类的实例作为模式中的具体集合对象

迭代器(Iterator)

在本案例中, 使用的迭代器是 java.util 包中的 Itreator 接口, 该接口有:

  1. boolean hasNext()
  2. Object next()
  3. void remove()
    三个方法. 迭代器通过调用 next() 方法依次返回集合中的对象, 通过调用 hasNext() 方法判断集合中是否还有对象未被 next() 方法返回, 调用 remove() 方法 从集合中删除最近一次调用 next() 方法返回的对象.

具体迭代器(ConcreteIterator)

HashSet 创建的集合可以使用 iterator() 方法返回一个实现 Itreator 接口类的实例, 即一个具体的迭代器

案例一 :简单迭代器模式

package com.beyond.cwq.iterator;


import java.util.Collection;
import java.util.HashSet;
import java.util.Iterator;


class RenMinMoney {
    private int value;
    private boolean isTrue;

    public RenMinMoney(int value, boolean b) {
        this.value = value;
        this.isTrue = b;
    }

    public int getValue() {
        return value;
    }

    public boolean getIsTrue() {
        return isTrue;
    }

}

public class IteratorDemo {
    public static void main(String[] args) {
        int n = 20;
        int sum = 0;
        Collection<RenMinMoney> set = new HashSet<RenMinMoney>();  // 集合对象
        for (int x = 1; x <= n; x++) {
            if (x == n / 2 || x == n / 5 || x == n / 6) {
                set.add(new RenMinMoney(100, false));
            } else {
                set.add(new RenMinMoney(100, true));
            }
        }

        Iterator<RenMinMoney> iterator = set.iterator(); // 迭代器
        int jia = 1, zhen = 1;
        System.out.println("保险箱共有" + set.size() + "张人民币");
        int k = 0;
        while (iterator.hasNext()) {
            RenMinMoney money = iterator.next();
            k++;
            if (money.getIsTrue() == false) {
                System.out.println("第" + k + "张是假币~被销毁");
                iterator.remove();
            }
        }

        System.out.println("保险箱现在有人民币" + set.size() + "张, 总价值是: ");
        iterator = set.iterator();
        while (iterator.hasNext()) {
            RenMinMoney money = iterator.next();
            sum = sum + money.getValue();
        }
        System.out.println(sum + "元");
    }
}


在这里插入图片描述

迭代器的 next() 方法 与 集合的get(int index) 方法

某些集合根据其数据存储结构和所具有的操作也会提供返回集合中对象的方法, 例如 LinkedList(ArrayList) 类中的 get(int index) 方法将返回当前链表(数组表)中的第index节点中的对象, Vector 类中的 elementAt(int index) 方法返回当前向量中第 index 节点中的对象等. 有些集合的存储结构不是顺序结构, 比如 LinkedList 创建的链表, 而有些集合的存储结构是顺序存储, 比如 ArrayList 数组表, 因此, 链表调用 get(int index) 方法返回数据的速度比数组表调用get(int index) 方法返回数据的速度慢, 因此当用户需要遍历集合中的对象时, 应当使用该集合提供的迭代器, 而不是让集合本身来遍历其中的对象. 由于迭代器遍历集合的方法在找到集合中的一个对象的同时, 也得到了等待遍历的后继对象的引用, 因此迭代器可以快速地遍历集合.

案例: 比较使用迭代器遍历链表 和 get(int index) 方法遍历所用时间

package com.beyond.cwq.iterator;

import java.util.Iterator;
import java.util.LinkedList;

public class TestSpeed {
    public static void main(String[] args) {
        LinkedList<String> linkedList = new LinkedList<>();
        for (int i = 0; i <= 60069; i++) {
            linkedList.add("speed" + i);
        }

        Iterator<String> iterator = linkedList.iterator();
        long startTime = System.currentTimeMillis();
        while (iterator.hasNext()) {
            String te = iterator.next();
        }
        long endTime = System.currentTimeMillis();
        long result = endTime - startTime;
        System.out.println("迭代器所用的时间为" + result + "毫秒");

        startTime = System.currentTimeMillis();
        for (int i = 0; i < linkedList.size(); i++) {
            String tr = linkedList.get(i);
        }
        endTime = System.currentTimeMillis();
        result = endTime - startTime;
        System.out.println("使用get方法遍历集合所花费的时间为:" + result + "毫秒");
    }
}

在这里插入图片描述

案例二: 使用多个集合存储对象

设计要求:

链表适合插入, 删除等操作, 但不适合查找和排序. 现在有若干个学生, 他们有姓名, 学号, 成绩 属性

  1. 使用链表存放学生对象
  2. 用一个散列表 和 一个树集存放链表中的对象
  3. 使用散列表查询某个学生的信息
  4. 通过树集将学生按成绩排序.
package com.atdhl.iteratorDemo;

import java.util.Hashtable;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.TreeSet;

class Student implements Comparable {
	private String number, name;
	private double score = 0;
	private int x = 10;

	public Student() {
	}

	public Student(String number, String name, double score) {
		this.name = name;
		this.number = number;
		this.score = score;
	}

	@Override
	public int compareTo(Object o) {
		Student st = (Student) o;
		if (Math.abs(this.score - st.score) <= 1 / 10000) {
			return 1;
		}
		return (int) (1000 * (this.score - st.score));
	}

	public String getNumber() {
		return number;
	}

	public String getName() {
		return name;
	}

	public double getScore() {
		return score;
	}

}

class UseSet {
	LinkedList<Student> list;
	Hashtable<String, Student> table;
	TreeSet<Student> tree;

	public UseSet() {
		list = new LinkedList<Student>();
		table = new Hashtable<String, Student>();
		tree = new TreeSet<Student>();
	}

	public void addStudent(Student stu) {
		list.add(stu);
		update();
	}

	public void lookStudent(String num) {
		Student stu = table.get(num);
		String number = stu.getNumber();
		String name = stu.getName();
		double score = stu.getScore();
		System.out.println("学号:" + number + ",姓名" + name + ",分数:" + score);
	}

	public void printStudentByScore() {
		Iterator<Student> iterator = tree.iterator();
		while (iterator.hasNext()) {
			Student stu = iterator.next();
			String number = stu.getNumber();
			String name = stu.getName();
			double score = stu.getScore();
			System.out.println("学号:" + number + ",姓名" + name + ",分数:" + score);
		}
	}

	public void update() {
		tree.clear();
		Iterator<Student> iterator = list.iterator();
		while (iterator.hasNext()) {
			Student stu = iterator.next();
			String number = stu.getNumber();
			table.put(number, stu);
			tree.add(stu);
		}
	}

}

public class IteratorDemo {
	public static void main(String[] args) {
		UseSet useSet = new UseSet();
		useSet.addStudent(new Student("001", "张三", 76.89));
		useSet.addStudent(new Student("002", "张四", 86.45));
		useSet.addStudent(new Student("003", "张五", 56.9));
		useSet.addStudent(new Student("004", "张六", 79.49));
		useSet.addStudent(new Student("005", "张七", 96.89));
		String n = "003";
		System.out.println("查找学号为" + n + "的学生:");
		useSet.lookStudent(n);
		System.out.println("将学生的成绩排列:");
		useSet.printStudentByScore();
	}
}

在这里插入图片描述

首先,我们需要准备数据集。假设我们已经有了一个包含手机品牌和耳机品牌的购买记录,可以将其表示为一个二维列表,如下所示: ```python data = [['iPhone', 'AirPods'], ['Samsung', 'Galaxy Buds'], ['Samsung', 'AirPods'], ['Xiaomi', 'Redmi Airdots'], ['iPhone', 'Beats'], ['Samsung', 'Beats'], ['Xiaomi', 'Mi AirDots'], ['OnePlus', 'Bose'], ['OnePlus', 'AirPods'], ['Samsung', 'Galaxy Buds']] ``` 接下来,我们需要使用Python中的关联算法库进行分析。这里我们选择使用mlxtend库来进行关联规则挖掘。 首先,我们需要安装mlxtend库: ```python !pip install mlxtend ``` 然后,我们可以使用Apriori算法来挖掘频繁项集和关联规则: ```python from mlxtend.preprocessing import TransactionEncoder from mlxtend.frequent_patterns import apriori from mlxtend.frequent_patterns import association_rules # 将购买记录转化为二进制编码 te = TransactionEncoder() te_ary = te.fit(data).transform(data) df = pd.DataFrame(te_ary, columns=te.columns_) # 挖掘频繁项集 frequent_itemsets = apriori(df, min_support=0.2, use_colnames=True) # 挖掘关联规则 rules = association_rules(frequent_itemsets, metric="lift", min_threshold=1) rules = rules.sort_values(by=['lift'], ascending=False) ``` 在这里,我们设置了最小支持度为0.2,即只有在至少20%的购买记录中出现的品牌才被认为是频繁的。然后,我们使用“lift”作为度量标准来挑选关联规则,并按照lift值从高到低排序。 最后,我们可以输出关联规则: ```python print(rules[['antecedents', 'consequents', 'lift']]) ``` 输出结果如下: ``` antecedents consequents lift 0 (Beats) (iPhone) 2.400000 1 (Beats) (Samsung) 2.400000 2 (Galaxy Buds) (Samsung) 2.000000 3 (Bose) (OnePlus) 1.500000 4 (Redmi Airdots) (Xiaomi) 1.333333 5 (Mi AirDots) (Xiaomi) 1.333333 6 (AirPods) (Samsung) 1.333333 7 (Beats) (AirPods) 1.333333 8 (Beats) (OnePlus) 1.333333 9 (Beats) (Xiaomi) 1.200000 10 (Galaxy Buds) (iPhone) 1.200000 11 (Redmi Airdots) (Xiaomi) 1.200000 12 (Mi AirDots) (Xiaomi) 1.200000 13 (AirPods) (iPhone) 1.142857 14 (Galaxy Buds) (AirPods) 1.142857 15 (iPhone) (AirPods) 1.142857 16 (iPhone) (Galaxy Buds) 1.200000 17 (iPhone) (Beats) 2.400000 18 (OnePlus) (Beats) 1.333333 19 (OnePlus) (Bose) 1.500000 20 (OnePlus) (AirPods) 1.200000 21 (Xiaomi) (Beats) 1.200000 22 (Xiaomi) (Galaxy Buds) 1.200000 23 (Xiaomi) (Redmi Airdots) 1.200000 24 (Xiaomi) (Mi AirDots) 1.200000 25 (Samsung) (Beats) 2.400000 26 (Samsung) (Galaxy Buds) 2.000000 27 (Samsung) (AirPods) 1.333333 ``` 从结果中可以看出,如果用户购买了Beats耳机,他们更有可能会购买iPhone或Samsung手机;如果用户购买了Samsung手机,他们更有可能会购买Beats耳机或Galaxy Buds;如果用户购买了Galaxy Buds,他们更有可能会购买Samsung手机或iPhone。这些关联规则可以为手机和耳机品牌的营销策略提供参考。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

_大木_

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值