2017-09-12 1 views
1

ArrayList 및 HashMaps를 사용하는 방법에 대한 멋진 솔루션을 많이 보았습니다.하지만 여전히 문제는 해결할 수 없습니다.HashMap에서 고유 한 값의 수를 계산하는 방법은 무엇입니까?

그래서 맥주, 와인 및 콜라를 마시는 사람들은 거의 없다는 생각이 들었습니다. 예를 들면 다음과 같습니다 :

Steve wine 
Steve cola 
Ben cola 
Frank wine 
Ben cola 
Ben cola 
Frank wine 

마지막으로 나는 마실 때마다 몇 잔의 술을 마셔야 하는지를 알아야합니다. 결과는 다음과 같습니다.

Steve wine 1 
Steve cola 1 
Ben cola 3 
Frank wine 2 

제 아이디어는 Person (String name, String drink) 개체를 만들기위한 것입니다. 그럼 모든 사람을 ArrayList에 넣었습니다. 그 후 HashMap을 만들었고 키가 존재하지 않으면 새로운 Person을 추가하고, 키가 이미 존재하면 1로 증가시킵니다.

Map<Person, Integer> map = new HashMap<Person, Integer>(); 

    for (Person p : persons) 
    { 
     if (map.containsKey(p)) { 
      map.put(p, map.get(p)+1); 
     } else { 
      map.put(p,1); 
     } 
    } 

작동하지 않습니다. 단지 다음과 같은 결과를 리턴합니다.

Steve wine 1 
Steve cola 1 
Ben cola 1 
Frank wine 1 
Ben cola 1 
Ben cola 1 
Frank wine 1 

그래서 저는 여기에 다른 트릭이 있어야한다는 것을 알고 있습니다. 어쩌면 당신은 HashMap을 사용하는 대신 음료의 안경을 세는 방법에 대한 다른 아이디어를 말할 수 있습니까? 많은 감사!

+9

Person 클래스에서 hashCode와 equals를 대체 했습니까? – Eran

+2

[HashSet의 복제본이 두 객체가 동일하다는 것을 인식하지 못하는 것 같습니다] (https://stackoverflow.com/questions/3692426/hashset-does-not-seem-to-realize-that-two-objects-are -the- same) – Ferrybig

답변

5

자바에게 여기에 8 개 스트림을 사용하면 하나 개의 영리 솔루션입니다 :

List<Person> people = Arrays.asList(new Person("Steve", "wine"), new Person("Steve", "cola"), 
      new Person("Ben", "cola"), new Person("Ben", "cola"), new Person("Steve", "wine"), 
      new Person("Steve", "wine")); 

    Map<Person, Long> map = people.stream() 
      .collect(Collectors.groupingBy(Function.identity(), Collectors.counting())); 

편집 : 는이 같은 정적 메소드를 가져올 수있는 코드를 감소 :

import static java.util.stream.Collectors.groupingBy; 
import static java.util.stream.Collectors.counting; 
import static java.util.function.Function.identity; 

및 다음 코드는 다음과 같습니다.

Map<Person, Long> map = people 
       .stream() 
       .collect(groupingBy(identity(), counting())); 
+0

코드의 1 줄에 아주 멋진 솔루션! 하지만 솔직히이 코드 줄 안에 정확히 무엇이 들어가는지 이해하지 못합니다. – Boris

1

Person 개체를 키로 저장하면 실수를 저 지르고 있습니다.

사람 이름, 문자열을 키로 저장해야하며 정상적으로 작동합니다.

ArrayList<String> list = new ArrayList<>(); 
list.add("Steve wine"); 
list.add("Steve cola"); 
list.add("Ben cola"); 
list.add("Frank wine"); 
list.add("Ben cola"); 
list.add("Ben cola"); 
list.add("Frank wine"); 

System.out.println(Collections.frequency(list, "Steve wine")); 

System.out.println(Collections.frequency(list, "Ben cola")); 
+0

'Map '는 그리 괜찮지 않습니까? – nullpointer

+0

아니요, 두 가지 선택이 있습니다. 1. 문자열 (이름)을 키로 사용하십시오. 또는. 2. Person을 키로 사용하지만 Person 클래스에서 hashcode() 및 equals() 메서드를 오버 라이딩하십시오. –

+0

@Seelenvirtuose가 업데이트되었는지 다시 확인하십시오. 친절하게 -1을 되돌립니다. 당신을 정정하는 대신 답을 downvoting 있습니다. –

6

덮어 쓰기 해시 코드와는 Person 클래스

0
int count = Collections.frequency("your collection", "Your Value"); 

내가 그런 말을하는 의미에서 방법 같습니다. 당신의 경우의 핵심은 스티브 콜라와 스티브 와인이 다르므로 사람이 아닌 다른 사람에게 주문하는 것입니다.

이후 : containsKey는 클래스에서 오버라이드하지 않으면 Object 클래스에서 상속 될 hashcode 메소드를 사용합니다. Object 클래스의 해시 코드는 인스턴스에 대해 다른 해시 코드를 제공하므로 클래스에서 해시 코드를 재정의해야합니다. 이름과 음료 (주문에 대한 고유 식별자)를 연결하고 해당 문자열에 대한 해시 코드 메서드를 호출하면 허용되는 해시 코드 메서드를 만들 수 있습니다. hascode에게 사람 클래스 방법을 동일 재정

+0

"귀하의 가치"란 무엇입니까? 나는 사람들의 이름이나 그들이 마시는 것을 미리 모른다. – Boris

+0

입력이 'Steve wine' –

+0

해결책을 업데이트했습니다. –

0

먼저 나는 당신의 인 이름을 돌봐 당신을 추천 할 것입니다 :

Map<String, Integer> map = new HashMap<>(); 

    for (Person p : persons) 
    { 
     if (map.containsKey(p.getName())) { 
      map.put(p.getName(), map.get(p)+1); 
     } else { 
      map.put(p.getName(),1); 
     } 
    } 
1

이 문제에 대한 솔루션입니다.

public class Person { 
     private String name; 
     private String drink; 

     public String getName() { 
      return name; 
     } 

     public void setName(String name) { 
      this.name = name; 
     } 

     public String getDrink() { 
      return drink; 
     } 

     public void setDrink(String drink) { 
      this.drink = drink; 
     } 

     @Override 
     public int hashCode() { 
      final int prime = 31; 
      int result = 1; 
      result = prime * result + ((drink == null) ? 0 : drink.hashCode()); 
      result = prime * result + ((name == null) ? 0 : name.hashCode()); 
      return result; 
     } 

     @Override 
     public boolean equals(Object obj) { 
      if (this == obj) 
        return true; 
      if (obj == null) 
        return false; 
      if (getClass() != obj.getClass()) 
        return false; 
      Person other = (Person) obj; 
      if (drink == null) { 
        if (other.drink != null) 
         return false; 
      } else if (!drink.equals(other.drink)) 
        return false; 
      if (name == null) { 
        if (other.name != null) 
         return false; 
      } else if (!name.equals(other.name)) 
        return false; 
      return true; 
     } 
} 
+0

예, 이제 작동합니다. 감사! Java 프로그래밍을 처음 접했고 전에는 HashCode 메서드를 재정의하지 않았습니다. 나는 이것이 그런 종류의 문제에 대한 훌륭하고보다 일반적인 해결책이라고 생각한다. – Boris

1

:

가정이 매개 변수 이름음료와 Person 클래스를 가지고는, 당신은 코드 아래 참조 해시 코드를 생성하는 일식처럼 어떤 IDE를 사용하고

위한 방법을 동일 수 Person 클래스에서 equals 및 hashCode 메소드를 대체해야합니다. 다음은 샘플 코드입니다 :이 후

class Person { 

    private String name; 
    private String drink; 

    public Person(String name, String drink) { 
    super(); 
    this.name = name; 
    this.drink = drink; 
    } 

    @Override 
    public int hashCode() { 

    return this.getName().hashCode(); 
    } 

    @Override 
    public boolean equals(Object obj) { 

    if (obj == this) 
     return true; 

    if (!(obj instanceof Person)) { 
     return false; 
    } 
    Person person = (Person) obj; 

    return person.getName().equals(this.name); 
    } 
    ....getters and setters 
    ....toString method 
} 

당신이 당신의 코드를 실행하려고하면이 코드 아래에 나를 위해 확실히 출력을 작동, 한

Map<Person, Integer> map = new HashMap<>(); 

    for (Person p : persons) 
    { 
     if (map.containsKey(p)) { 
      map.put(p, map.get(p)+1); 
     } else { 
      map.put(p,1); 
     } 
    } 

    for(Map.Entry<Person, Integer> person : map.entrySet()){ 
     System.out.println(person.getKey()+" "+person.getValue()); 
    } 

출력 :

Person [name=Steve, drink=wine] 2 
Person [name=Ben, drink=cola] 3 
Person [name=Frank, drink=wine] 2 

희망이 도움이 될 것입니다.

1

키는 해시 맵 또는 사전 (C#)에서 고유해야합니다. 이 경우 열쇠 자체를 삽입하는 동안 이름과 음료를 결합해야합니다. C#에서 솔루션을 제공합니다. 희망이 도움이됩니다.

public class Person 
{ 
    public string Name { get; set; } 
    public string Drink { get; set; } 
} 

class Program 
{ 
    static void Main(string[] args) 
    { 
     List<Person> persons = new List<Person>(); 
     persons.Add(new Person() { Name = "Steve", Drink = "Tea" }); 
     persons.Add(new Person() { Name = "Bell", Drink = "Milk" }); 
     persons.Add(new Person() { Name = "Bell", Drink = "Milk" }); 
     persons.Add(new Person() { Name = "Bell", Drink = "Milk" }); 
     persons.Add(new Person() { Name = "Steve", Drink = "Milk" }); 
     Dictionary<string, int> output = new Dictionary<string, int>(); 
     foreach(var p in persons) 
     { 
      string key = p.Name + ":" + p.Drink; 
      if(output.ContainsKey(key)) 
      { 
       output[key]++; 
      } 
      else 
      { 
       output.Add(key,1); 
      } 
     } 
     foreach(var k in output) 
     { 
      string[] split = k.Key.Split(':'); 
      Console.WriteLine(string.Format("{0} {1} {2}", split[0],split[1],k.Value.ToString())); 
     } 
    } 
} 
+0

OP에서 작동하는 언어가 아닙니다. Java에서 구현이 다르다는 점을 고려하면 도움이되지 않습니다. – Assafs

관련 문제