Java 基于另一个流过滤一个流并收集

Java Filter one stream based on another stream and collect

我有这段代码使用 for 循环和 steam,但我想知道我可以使用两个流来改进它。在这里,我想用流替换 for 循环,并希望获得方法 returns.

的字符串列表
public class City {
    
    final int x;
    final int y;
    final String name;
    public City(String name, int x, int y) {
        this.name = name;
        this.x = x;
        this.y = y;
    }
    public int getX() {
        return x;
    }
    public int getY() {
        return y;
    }
    public String getName() {
        return name;
    }
}



import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
        public class Test {
        
            public static boolean cityFilter(City city, City c) {
                return !city.getName().equals(c.getName()) && (city.getX()==c.getX() || city.getY()==c.getY())?true:false;
            }
        
            public static int compareCities(City c, City c1, City c2) {
                int dis1 = Math.abs(c.getX() - c1.getX()) + Math.abs(c.getY() - c1.getY());
                int dis2 = Math.abs(c.getX() - c2.getX()) + Math.abs(c.getY() - c2.getY());
                return dis1==dis2?c.getName().compareTo(c2.getName()):dis1-dis2;
            }
            
            public static List<String> filterAndFindCities(List<String> c, List<Integer> x, List<Integer> y, List<String> q) {
                Map<String, City> cityMap = IntStream.range(0, c.size()).boxed().collect(Collectors.toMap(c::get, i-> new City(c.get(i), x.get(i), y.get(i))));
                List<String> rst = new ArrayList<String>();
    //====How can I replace this for loop with a stream and get a list of String?===
                for (String s : q) {
                    City givenCity = cityMap.get(s);
                    City nearest = cityMap.values().stream().filter(p -> cityFilter(givenCity, p))
                                            .sorted((c1, c2) -> compareCities(givenCity, c1, c2))
                                            .findFirst().orElse(null);
                    String nearestCity = nearest != null ? nearest.getName() : "EMPTY";
                    rst.add(nearestCity);
                }
                return rst;
            }
        }

我找到了一个快速而肮脏的解决方案,当然不是最好的,但我肯定可以改进它。

public static List<String> filterAndFindCities(List<String> c, List<Integer> x, List<Integer> y, List<String> q) {

Map<String, City> cityMap = IntStream.range(0, c.size()).boxed()
                            .collect(Collectors
                            .toMap(c::get, i -> new City(c.get(i), x.get(i), 
                                                                    y.get(i))));
return q.stream()
       .map(name ->cityMap.values().stream()
         .filter(p -> cityFilter(cityMap.get(name), p))
         .sorted((c1, c2) -> compareCities(cityMap.get(name), c1, c2))
         .findFirst().orElse(null))
       .map(p->p!=null?p.getName():"EMPTY")
       .collect(Collectors.toList());
}