Java集合 - 打印按人口,城市和州排序的州际公路

时间:2017-10-02 17:07:06

标签: java sorting collections

我正在研究我在接受采访时遇到的问题。

输入包含 人口|城市|州|州际列表

输出需要先按人口按降序排序,然后按城市和州按字母顺序排序,然后州际公路也需要按升序排序。

示例输入:

27|Chicago|Illinois|I-94;I-90;I-88;I-57;I-55
83|New York|New York|I-78;I-95;I-87;I-80
15|Phoenix|Arizona|I-10;I-17;I-8
15|Philadelphia|Pennsylvania|I-95;I-76

示例输出:

83

New York, New York
Interstates: I-78, I-80, I-87, I-95

27

Chicago, Illinois
Interstates: I-55, I-57, I-88, I-90, I-94

15

Philadelphia, Pennsylvania
Interstates: I-76, I-95

Phoenix, Arizona
Interstates: I-8, I-10, I-17

到目前为止,这是我的方法。我目前陷入if块,我已添加评论。我不确定我是否朝着正确的方向前进。我正在寻找一个提示,采取正确的方法。

Scanner sc = new Scanner(System.in);
String line;
List<String> al = new ArrayList<>();

//Outer map sorts reverse by population, inner map1 sorts by city, inner 
map2 sorts by state
Map<Integer, Map<String, Map<String, String>>> outerMap = new TreeMap<>
(Collections.reverseOrder());
Map<String, Map<String, String>> innerMap1 = new TreeMap<>();
Map<String, String> innerMap2 = new TreeMap<>();

while(sc.hasNextLine() && (line = sc.nextLine()).length()!=0) {

  //Ignore if input contains this character
  if(line.contains("#")) {
    line = sc.nextLine();
  }

  al.add(line);
}

for(int i = 0; i < al.size(); i++) {

  int outerMapKey = Integer.parseInt(al.get(i).split("\\|")[0]);
  String innerMap1Key = al.get(i).split("\\|")[1];
  String innerMap2Key = al.get(i).split("\\|")[2];

  String value = al.get(i);

  outerMap.get(outerMapKey);

  if(outerMap.containsKey(outerMapKey)) {


    innerMap1 = outerMap.get(outerMapKey);
    /* Logic to put values in inner maps 
    This is going to get very convoluted, not sure if I have the 
    right approach
    */
  }
  else {
    innerMap1 = new TreeMap<>();
    innerMap2 = new TreeMap<>();
    innerMap2.put(innerMap2Key, value);
    innerMap1.put(innerMap1Key, innerMap2);
    outerMap.put(outerMapKey, innerMap1);
  }
  }

到目前为止,感谢您的帮助。我根据这里的反馈发布我的代码(现在正在工作)。请看一下并建议如何改进它。

public static void main(String[] args) {

    Map<String, List<PopulationByCityState>> map = readAndProcessInput();
    printSortedOutput(map);

}


private static Map<String, List<PopulationByCityState>> readAndProcessInput() {

    Map<String, List<PopulationByCityState>> map = readInput();
    sortByPopulationCityAndState(map);
    return map;
}

private static Map<String, List<PopulationByCityState>> readInput() {
    System.out.println("Enter input:");
    Scanner sc = new Scanner(System.in);
    String line;
    Map<String, List<PopulationByCityState>> map = new TreeMap<>(Collections.reverseOrder());

    while (sc.hasNextLine() && (line = sc.nextLine()).length() != 0) {
        if (line.contains("#")) {
            line = sc.nextLine();
        }

        populateMap(line, map);

    }
    return map;
}

private static void populateMap(String line, Map<String, List<PopulationByCityState>> map) {

    String[] s = line.split("\\|");
    String[] is = s[3].split(";");
    String key = s[0];
    PopulationByCityState p = new PopulationByCityState();
    p.setPopulation(Long.parseLong(s[0]));
    p.setCity(s[1]);
    p.setState(s[2]);
    List<String> interstates = new ArrayList<>();


    for (String aString : is) {
        interstates.add(aString);
    }

    sortInterstates(interstates);
    p.setInterstates(interstates);

    if (map.containsKey(key)) {
        map.get(key).add(p);
    } else {
        List<PopulationByCityState> al = new ArrayList<>();
        al.add(p);
        map.put(key, al);
    }
}

private static void sortInterstates(List<String> interstates) {
    Collections.sort(interstates, new Comparator<String>() {
        @Override
        public int compare(String o1, String o2) {
            int n1 = Integer.parseInt(o1.split("-")[1]);
            int n2 = Integer.parseInt(o2.split("-")[1]);

            return n1 - n2;
        }
    });
}

private static void sortByPopulationCityAndState(Map<String, List<PopulationByCityState>> map) {
    for (Map.Entry entry : map.entrySet()) {

        List<PopulationByCityState> list = (List<PopulationByCityState>) entry.getValue();


        Collections.sort(list, new Comparator<PopulationByCityState>() {
            @Override
            public int compare(PopulationByCityState o1, PopulationByCityState o2) {
                int c;
                c = (int) (o2.getPopulation() - o1.getPopulation());
                if (c == 0) {
                    c = o1.getCity().compareTo(o2.getCity());
                }
                if (c == 0) {
                    c = o1.getState().compareTo(o2.getState());
                }
                return c;
            }
        });
    }
}

private static void printSortedOutput(Map<String, List<PopulationByCityState>> map) {

    for (Map.Entry<String, List<PopulationByCityState>> entry : map.entrySet()) {
        System.out.println(entry.getKey());
        System.out.println();

        List<PopulationByCityState> list = entry.getValue();

        for (PopulationByCityState p : list) {
            System.out.println(p.getCity() + ", " + p.getState());
            List<String> interstates = p.getInterstates();
            System.out.print("Interstates: ");
            int s = 0;

            for (String is : interstates) {
                s++;
                System.out.print(is);
                if (s != interstates.size()) {
                    System.out.print(", ");
                }

            }
            System.out.println();
            System.out.println();
        }


    }
}

2 个答案:

答案 0 :(得分:1)

您的方法依赖于复杂且无意义的结构,并且还使用仅对地图的第一级进行排序的比较器:

Map<Integer, Map<String, Map<String, String>>> outerMap = new TreeMap<>
(Collections.reverseOrder());

更精细的方法可以依赖于使用一个类来表示您需要代表州的人口所需的每个个人信息:PopulationForState

这是一个非常简单的表示(当然这是可以改进的,但这应该有助于你理解逻辑):

public class PopulationForState{
  private long population;
  private String city;
  private String state;
  private List<String> interstates;
 ...
    // getters 
}

List中添加它们的实例并使用比较器按比例按降序排序,然后按城市和州的字母顺序排序。
在外部元素的排序期间,interstates字段可以独立地或直接地排序 您可以在PopulationForState中提供排序方法,例如sortInnerStates(),按升序对其进行排序。

就个人而言,我会独立完成,以保持处理之间不那么耦合。

所以你可以这样写:

List<PopulationForState> populationForStates = new ArrayList<>();
populationForStates.add(new PopulationForState(...));
populationForStates.add(new PopulationForState(...));

Collection.sort(populationForStates, Comparator.comparing(PopulationForState::population).reversed()
          .thenComparing(PopulationForState::getCity)
          .thenComparing(PopulationForState::getState);

populationForStates.stream()
                   .forEach(PopulationForState::sortInnerStates);

答案 1 :(得分:1)

如果你有一个结构,如上面发布的那个结构:

public class PopulationForState{
 public long population;
 public String city;
 public String state;
 public List<String> interstates;
 //Do encapsulate
}

您可以使用一个比较器对其进行排序:

Collections.sort(populatisForStates, new Comparator<PopulationForState>(){
   public int compare(PopulationForState first, PopulationForState scnd) {
      int compare = first.population - scnd.population;
      if(compare != 0) return compare;
      compare = first.city.compareTo(scnd.city);
      if(compare != 0) return compare;
      return first.state.compareTo(scnd.state);
   }
});

排序Interstates类似,您只需在每个实例上使用Collections.sort(interstates)。