#java
#java
Вопрос:
Вопрос в названии: у меня есть класс, который сопоставляет некоторых исполнителей с их соответствующим жанром. Считывает данные из текстового файла со строками, содержащими «жанр исполнителя», например, «ACDC Rock». В частности, у меня возникли проблемы с классом getArtists(String genre, int n). Как я могу вернуть n количество исполнителей в определенном жанре? Я предполагаю, что мне нужно создать цикл for от 0 до n, затем, если карта содержит этот жанр, каким-то образом верните исполнителей, но я не понимаю, как это сделать. Вот что я пробовал:
public String getArtists(String genre, int n)
{
for (int i = 0; i <= n; i ) {
if (map.containsValue(genre)){
}
}
return "";
}
Вот остальная часть класса:
public class Artists {
Map<String,String> map;
public Artists()
{
map = new TreeMap<>();
}
public boolean readArtists(String textFile)
{
Scanner file, lineScan;
boolean success = true;
try
{
file = new Scanner(new File(textFile));
while (file.hasNext())
{
String line = file.nextLine();
String[] parts = line.split(" ");
map.put(parts[0].toUpperCase().replace('_',' '), parts[1]);
}
}
catch (FileNotFoundException exception)
{
success = false;
}
return success;
}
public void addArtist (String artist, String genre)
{
map.put(artist.toUpperCase(), genre);
}
public void display()
{
System.out.printf("%-30s %sn", "ARTIST", "GENRE");
System.out.printf("%-30s %sn", "------", "-----");
Set<String> artists = map.keySet();
for (String artist: artists)
System.out.printf("%-30s %sn", artist, map.get(artist));
}
/**
Returns a formatted list of at most n artists of the given genre.
@param genre the genre of artists to be included
@param n the maximum number of artists to be included
@return a list containing at most n artists of the given genre
*/
public String getArtists(String genre, int n)
{
for (int i = 0; i <= n; i ) {
if (map.containsValue(genre)){
}
}
return "";
}
public static void main(String[] args)
{
Artists artists = new Artists();
artists.readArtists("artists30.txt");
artists.addArtist("ACDC", "Rock");
artists.display();
System.out.println(artists.getArtists("Rock", 10));
System.out.println(artists.getArtists("Country", 10));
}
}
Комментарии:
1. Вы, конечно, хотите вернуть a
List<String>
, а не одну строку?2. @BillCosby Пожалуйста, не меняйте принципиально свой вопрос после получения ответов. Это аннулирует время, потраченное другими на ответ на ваш вопрос.
Ответ №1:
Переберите всю карту, затем добавьте ключ (исполнителя) в список, когда найдете подходящий жанр
List<String> result = new ArrayList<>();
map.forEach((k, v) -> {
if (v.equals(genre) amp;amp; result.size() < n) result.add(k);
});
return resu<
Комментарии:
1. Не уверен, почему вы хотели бы использовать итератор… Конечно, вы можете использовать StringBuilder вместо списка, но в комментарии к методу явно указано «вернуть список». У вас может быть отдельный метод, который форматирует список в строку
2. Конечно, вы можете
map.forEach
заменить циклом overIterator<Map.Entry>
иList
withStringBuilder
. Логика остается той же
Ответ №2:
Я бы рекомендовал создать класс для исполнителей, который содержит информацию следующим образом:
class ArtistInfo{
String name;
String genre;
ArtistInfo(String name, String genre) {
this.name = name;
this.genre = genre;
}
}
и затем вы можете выполнить множество действий, таких как фильтр в списке массивов, например:
ArrayList<ArtistInfo> ai = new ArrayList<>();
ai.add(new ArtistInfo("ACDC", "Rock"));
Stream<ArtistInfo> filteredList = ai.stream().filter(n -> n.genre.equals("Rock"));
а затем получить количество:
long count = filteredList.count();
count
это количество исполнителей с жанром «Рок».
Ответ №3:
Вероятно, у вас должно быть отображение из жанра в список исполнителей вместо сопоставления исполнителя с жанром, что-то вроде этого:
Map<String,List<String>> map;
public void addArtist (String artist, String genre)
{
map.computeIfAbsent(genre, genre -> new LinkedList<>()).add(artist);
}
public List<String> getArtists(String genre, int n) {
ArrayList<String> result = new ArrayList<>(n);
List<String> mapList = map.get(genre);
if (mapList == null)
return resu<
for (int i = 0; i < n amp;amp; i < mapList.size(); i)
result.add(mapList.get(i));
}
Если вы хотите сохранить свою карту, вы также можете сделать что-то вроде:
public List<String> getArtists(String genre, int n) {
return map.entrySet().stream().filter(entry -> genre.equals(entry.getValue())).limit(n).map(entry -> entry.getKey()).collect(Collectors.toList());
}
Чтобы ответить на ваш комментарий, если вы хотите вернуть одну строку, вы можете сделать что-то вроде этого:
public String getArtists(String genre, int n) {
StringBuilder result = new StringBuilder();
map.entrySet().stream().filter(entry -> genre.equals(entry.getValue())).limit(n).forEach(entry -> result.append(entry.getKey());
return resu<
}
Или, поскольку я предполагаю, что вы новичок и можете не использоваться с потоками, простой способ, не такой оптимизированный, но может быть более понятным:
public String getArtists(String genre, int n) {
StringBuilder result = new StringBuilder();
int count = 0;
for (Map.Entry<String, String> entry : map.entrySet()) {
if (count >= n)
break; // if we already reach the limit n, stop the loop
if (!genre.equals(entry.getValue())
continue; // if this is not an artist of the genre we are looking for, skip it
if (result.length() > 0)
result.append(", "); // if this is not the first, add a comma so it is prettier
result.append(entry.getKey()); // append the name of the artist
count ; // increment the counter
}
return resu<
}
Много способов
Ответ №4:
Вот простое решение. Мы сканируем все значения и сравниваем каждое значение с жанром и возвращаем первый n результат.
public String getArtists(String genre, int n)
{
List<String> artists = new ArrayList<>();
map.forEach((key,value)-> {
if(value.equals(genre)){
if(artists.size() < n) artists.add(key);
}
});
StringBuilder artistsAsString = new StringBuilder();
for(String artist : artists){
artistsAsString.append(artist).append(" ");
}
return artistsAsString.toString();
}