2

I have a file that looks like this:

User -> Artist
u1 -> a1
u1 -> a15
u1 -> a123
u2 -> a1
u2 -> a32
...
u1800 -> a56

which tells us which artists every user has listened to.

How can I import this in a two-dimensional array (or maybe another more appropriate data-structure?) in which every row will be a user and every [row][column] one of the artists the user has listened to?

I want to end up storing that u1 has listened to {a1, a15, a123} etc

3 Answers 3

3

You could store this information in a Map. Suppose you have an User class and an Artist class, you could create a Map<User, Set<Artist>> that would keep a set (or list if you prefer) of artists for each user.

To create the map you do:

Map<User, Set<Artist>> artistsFromUser = new HashMap<>();

If you just need to store the usernames and artist names as strings, your map can be:

Map<String, Set<String>> artistsFromUser = new HashMap<>();

Then you will need to run through your file, transforming each user -> artist pair into an user object and an artist object. After that, you can store the artist using the corresponding user reference:

// Retrieve the set of artists for this user
// Substitute String for Artist here if you're just storing the names
Set<Artist> artists = artistsFromUser.get(user);
if (artists == null) {
    // If the set was not created for this user yet
    // you need to create it and store it in the map
    artists = new HashSet<>();
    artistsFromUser.put(user, artists);
}
// Add the new artist to the set
artists.add(artist);

Printing your output would be as simple as doing:

System.out.println(user + " has listened to " + artistsFromUser.get(user));
Sign up to request clarification or add additional context in comments.

Comments

2

Having read your file into a List<String>, it's a one-liner:

Map<String, List<String>> map = lines.stream()
    .map(s -> s.split(" -> "))
    .collect(Collectors.groupingBy(a -> a[0]))
    .entries().stream()
    .toMap(e -> e.getKey(), e -> e.getValue().stream()
        .map(a -> a[1]).collect(Collectors.toList()));

Disclaimer: Code thumbed in on phone - may contain syntax errors

1 Comment

@apgp88 yes. this is a java 8 solution. Java 8 has been out for a year now, so java 8 is the mainstream version now
0

Google Guava Multimap is the exact structure for this. A Multimap<K, V> is conceptually the same as a Map<K, Collection<V>>, which is what you want.

In particular, a ListMultimap would be ideal for your case. You could use a mix of Guava & Java 8 to satisfy your requirements:

public class FileParser {

    public static void main(String[] args) throws IOException {

        // Path to file
        Path path = Paths.get("fileparser-test.txt");

        // Process file line by line, skipping first
        // one and splitting to get user and artist
        Iterator<String[]> splittedLinesIterator = 
                Files.lines(path).skip(1).
                map(s -> s.split(" -> ")).iterator();

        // Create multimap, indexing by the first element of array
        ListMultimap<String, String[]> multimap = 
                Multimaps.index(splittedLinesIterator, s -> s[0]);

        // Transform values by only keeping second element of array
        ListMultimap<String, String> result = 
                Multimaps.transformValues(multimap, s -> s[1]);

        System.out.println(result); // {u1=[a1, a15, a123], u2=[a1, a32]}
    }
}

Please see Files.lines(), Multimaps.index() and Multimaps.transformValues() docs for further reference.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.