基于共同 属性 组合集合的智能方式
Smart way to combine collections based on a common property
假设我有以下两个 classes...
public class Computer {
private String computerName;
private boolean hasTechnicalIssue;
}
public class TechnicalIssue {
private String issueId;
private String computerName;
}
public class ComputerManager {
ComputerDao computerDao;
IssueDao issueDao;
public void getComputers {
List<Computer> computers = computerDao.getComputers();
List<TechnicalIssues> technicalIssues = issueDao.getTechnicalIssues();
// I would like to do something here to set the hasTechnicalIssue flag
}
}
计算机 class 和技术问题 class 都有一个计算机名称 属性。
是否有使用 Guava 的聪明方法,我可以使用 TechnicalIssues 列表中的计算机名称 属性 在计算机列表中设置 hasTechnicalIssue 布尔值?
例如,如果包含计算机的列表包含计算机名称为 computer9999 的条目,并且包含技术问题的列表也包含具有相同计算机名称的条目,则计算机 class 上的 hasTechnicalIssue 应该等于 true。
class Computer {
private String computerName;
private boolean hasTechnicalIssue;
public String getComputerName() {
return computerName;
}
public void setComputerName(String computerName) {
this.computerName = computerName;
}
public boolean isHasTechnicalIssue() {
return hasTechnicalIssue;
}
public void setHasTechnicalIssue(boolean hasTechnicalIssue) {
this.hasTechnicalIssue = hasTechnicalIssue;
}
}
class 技术问题 {
private String issueId;
private String computerName;
public String getComputerName() {
return computerName;
}
public void setComputerName(String computerName) {
this.computerName = computerName;
}
public String getIssueId() {
return issueId;
}
public void setIssueId(String issueId) {
this.issueId = issueId;
}
}
class ComputerDao {
List<Computer> getComputers() {
List<Computer> clist = new ArrayList<Computer>();
Computer c = new Computer();
c.setComputerName("rahul");
c.setHasTechnicalIssue(true);
clist.add(c);
Computer c1 = new Computer();
c1.setComputerName("rahul1");
c1.setHasTechnicalIssue(false);
clist.add(c1);
return clist;
}
}
class IssueDao {
List<TechnicalIssue> getTechnicalIssues() {
List<TechnicalIssue> clist = new ArrayList<TechnicalIssue>();
TechnicalIssue c = new TechnicalIssue();
c.setComputerName("rahul");
c.setIssueId("111");
clist.add(c);
TechnicalIssue c1 = new TechnicalIssue();
c1.setComputerName("rahul1");
c1.setIssueId("112");
clist.add(c1);
return clist;
}
}
public class 问题类 {
ComputerDao computerDao;
IssueDao issueDao;
public void getComputers() {
computerDao = new ComputerDao();
issueDao = new IssueDao();
List<Computer> computers = computerDao.getComputers();
List<TechnicalIssue> technicalIssues = issueDao.getTechnicalIssues();
for (Iterator<TechnicalIssue> it = technicalIssues.iterator(); it.hasNext();) {
TechnicalIssue technicalIssue = it.next();
for (Iterator<Computer> it1 = computers.iterator(); it1.hasNext();) {
Computer computers1 = it1.next();
if (technicalIssue.getComputerName().equals(computers1.getComputerName()) && computers1.isHasTechnicalIssue()) {
System.out.println("Has techincal issue : " + computers1.getComputerName());
//Print all other details
}
}
}
}
public static void main(String[] args) {
QuestionClass QC = new QuestionClass();
QC.getComputers();
}
}
## 输出 ##
有技术问题:rahul
构建成功(总时间:0 秒)
你特地问了一个涉及Guava的解决方案。我从未使用过番石榴。如果您不介意,我可以简单地告诉您如何操作:
for (int i = 0; i < computers.size(); i++){
String cn = computers.get(i).getComputerName();
for (int j = 0; j < technicalIssues.size(); j++){
if (cn.contentEquals(technicalIssues.get(j).getComputerName())){
computers.get(i).setHasTechnicalIssue(true);
break;
}
}
}
这听起来像是 FluentIterable
的方法和 anyMatch
运算符的使用。主要注意事项:
- 我们不在乎匹配出现在技术问题列表中的什么地方,只要有匹配
- 我们需要遍历计算机集合中的所有元素
- 这仍然是一项昂贵的操作,因为我们正在拉削 O(nm)
考虑到这一点,流畅的可迭代表达式就很简单了。
final FluentIterable<TechnicalIssue> fluentIterable = FluentIterable.from(technicalIssues);
for(Computer computer : computers) {
boolean match = fluentIterable.anyMatch(new Predicate<TechnicalIssue>() {
@Override
public boolean apply(final TechnicalIssue input) {
return input.getComputerName().equals(computer.getComputerName());
}
});
if(match) {
computer.setHasTechnicalIssue(true);
}
}
为了避免 O(n*m) 算法(O(n^2) 假设 2 个集合具有可比较的大小),您需要对每个集合迭代一次,如果您收集中间集合,这是可能的,即涉及技术问题的计算机名称:
Set<String> computersWithIssues = Sets.newHashSetWithExpectedSize(technicalIssues.size());
for (TechnicalIssue issue : technicalIssues) {
computersWithIssues.add(issue.getComputerName());
}
for (Computer computer : computers) {
computer.setHasTechnicalIssue(computersWithIssues.contains(computer.getComputerName());
}
您可能会喜欢上 Guava 并使用 Function<TechnicalIssue, String>
将技术问题集合转换为名称集合,但除非您出于某些原因需要概括,否则这里只是杂音.参见Guava函数概念解释中的caveat,重点是写的时候不是更清楚就是更短:
Function<TechnicalIssue, String> toName = new Function<>() {
@Override
public String apply(TechnicalIssue input) {
return input.getComputerName();
}
}
Set<String> computersWithIssues = FluentIterable.from(technicalIssues)
.transform(toName)
.toSet();
假设我有以下两个 classes...
public class Computer {
private String computerName;
private boolean hasTechnicalIssue;
}
public class TechnicalIssue {
private String issueId;
private String computerName;
}
public class ComputerManager {
ComputerDao computerDao;
IssueDao issueDao;
public void getComputers {
List<Computer> computers = computerDao.getComputers();
List<TechnicalIssues> technicalIssues = issueDao.getTechnicalIssues();
// I would like to do something here to set the hasTechnicalIssue flag
}
}
计算机 class 和技术问题 class 都有一个计算机名称 属性。
是否有使用 Guava 的聪明方法,我可以使用 TechnicalIssues 列表中的计算机名称 属性 在计算机列表中设置 hasTechnicalIssue 布尔值?
例如,如果包含计算机的列表包含计算机名称为 computer9999 的条目,并且包含技术问题的列表也包含具有相同计算机名称的条目,则计算机 class 上的 hasTechnicalIssue 应该等于 true。
class Computer {
private String computerName;
private boolean hasTechnicalIssue;
public String getComputerName() {
return computerName;
}
public void setComputerName(String computerName) {
this.computerName = computerName;
}
public boolean isHasTechnicalIssue() {
return hasTechnicalIssue;
}
public void setHasTechnicalIssue(boolean hasTechnicalIssue) {
this.hasTechnicalIssue = hasTechnicalIssue;
}
}
class 技术问题 {
private String issueId;
private String computerName;
public String getComputerName() {
return computerName;
}
public void setComputerName(String computerName) {
this.computerName = computerName;
}
public String getIssueId() {
return issueId;
}
public void setIssueId(String issueId) {
this.issueId = issueId;
}
}
class ComputerDao {
List<Computer> getComputers() {
List<Computer> clist = new ArrayList<Computer>();
Computer c = new Computer();
c.setComputerName("rahul");
c.setHasTechnicalIssue(true);
clist.add(c);
Computer c1 = new Computer();
c1.setComputerName("rahul1");
c1.setHasTechnicalIssue(false);
clist.add(c1);
return clist;
}
}
class IssueDao {
List<TechnicalIssue> getTechnicalIssues() {
List<TechnicalIssue> clist = new ArrayList<TechnicalIssue>();
TechnicalIssue c = new TechnicalIssue();
c.setComputerName("rahul");
c.setIssueId("111");
clist.add(c);
TechnicalIssue c1 = new TechnicalIssue();
c1.setComputerName("rahul1");
c1.setIssueId("112");
clist.add(c1);
return clist;
}
}
public class 问题类 {
ComputerDao computerDao;
IssueDao issueDao;
public void getComputers() {
computerDao = new ComputerDao();
issueDao = new IssueDao();
List<Computer> computers = computerDao.getComputers();
List<TechnicalIssue> technicalIssues = issueDao.getTechnicalIssues();
for (Iterator<TechnicalIssue> it = technicalIssues.iterator(); it.hasNext();) {
TechnicalIssue technicalIssue = it.next();
for (Iterator<Computer> it1 = computers.iterator(); it1.hasNext();) {
Computer computers1 = it1.next();
if (technicalIssue.getComputerName().equals(computers1.getComputerName()) && computers1.isHasTechnicalIssue()) {
System.out.println("Has techincal issue : " + computers1.getComputerName());
//Print all other details
}
}
}
}
public static void main(String[] args) {
QuestionClass QC = new QuestionClass();
QC.getComputers();
}
}
## 输出 ##
有技术问题:rahul
构建成功(总时间:0 秒)
你特地问了一个涉及Guava的解决方案。我从未使用过番石榴。如果您不介意,我可以简单地告诉您如何操作:
for (int i = 0; i < computers.size(); i++){
String cn = computers.get(i).getComputerName();
for (int j = 0; j < technicalIssues.size(); j++){
if (cn.contentEquals(technicalIssues.get(j).getComputerName())){
computers.get(i).setHasTechnicalIssue(true);
break;
}
}
}
这听起来像是 FluentIterable
的方法和 anyMatch
运算符的使用。主要注意事项:
- 我们不在乎匹配出现在技术问题列表中的什么地方,只要有匹配
- 我们需要遍历计算机集合中的所有元素
- 这仍然是一项昂贵的操作,因为我们正在拉削 O(nm)
考虑到这一点,流畅的可迭代表达式就很简单了。
final FluentIterable<TechnicalIssue> fluentIterable = FluentIterable.from(technicalIssues);
for(Computer computer : computers) {
boolean match = fluentIterable.anyMatch(new Predicate<TechnicalIssue>() {
@Override
public boolean apply(final TechnicalIssue input) {
return input.getComputerName().equals(computer.getComputerName());
}
});
if(match) {
computer.setHasTechnicalIssue(true);
}
}
为了避免 O(n*m) 算法(O(n^2) 假设 2 个集合具有可比较的大小),您需要对每个集合迭代一次,如果您收集中间集合,这是可能的,即涉及技术问题的计算机名称:
Set<String> computersWithIssues = Sets.newHashSetWithExpectedSize(technicalIssues.size());
for (TechnicalIssue issue : technicalIssues) {
computersWithIssues.add(issue.getComputerName());
}
for (Computer computer : computers) {
computer.setHasTechnicalIssue(computersWithIssues.contains(computer.getComputerName());
}
您可能会喜欢上 Guava 并使用 Function<TechnicalIssue, String>
将技术问题集合转换为名称集合,但除非您出于某些原因需要概括,否则这里只是杂音.参见Guava函数概念解释中的caveat,重点是写的时候不是更清楚就是更短:
Function<TechnicalIssue, String> toName = new Function<>() {
@Override
public String apply(TechnicalIssue input) {
return input.getComputerName();
}
}
Set<String> computersWithIssues = FluentIterable.from(technicalIssues)
.transform(toName)
.toSet();