Click here to Skip to main content
15,888,124 members
Please Sign up or sign in to vote.
0.00/5 (No votes)
See more:
Hi all, I have two lists of classes as shown below - both classe have a common property - using Linq how can I remove items from the artist list that don't have any Albums ? In SQL I would say

C#
Delete from Artist where ArtistName not in(Select ArtistName from Albums)


class Artist
{
    String ArtistName {get;set;}
}

class Albums
{
    String ArtistName {get;set;}
    String AlbumName {get;set;}
}
Posted
Comments
BillWoodruff 3-Dec-15 13:50pm    
An artist with no albums stops being an artist ? An album can have only one artist ?

I think the design of your classes should reflect your estimation of the most frequently used type of queries users will want to do.

I also think that unless you are absolutely certain the design requirement will never change, it is best to implement general solutons that anticipate being extended, changed, in the future.

If you are really interested in this type of approach, let me know, and I'll post an example.
pkfox 3-Dec-15 14:29pm    
I know what your saying Bill but the data is coming from a source that is not under my control, it's a music database and an artist can exist if they contribute to an album but are not necessarily the *album artist* so an entry is made as a *contributor* but not a corresponding album
BillWoodruff 4-Dec-15 2:18am    
Hi PkFox, Understood. Is it the case that the data you receive, for each album, contains both a list of "primary" artists, and another list of "contributing artists" ? Is it the case that you are getting Artists information always combined with Album data ?

Even though you may have no control over the incoming JSON, that doesn't stop you transforming those "resurrected" class instances into a structure you design to meet the possible modal needs of your users ... does it ?

cheer, Bill
pkfox 4-Dec-15 3:18am    
Food for thought thanks Bill - you mentioned you could send me something - please do.
BillWoodruff 4-Dec-15 3:33am    
"you mentioned you could send me something - please do" I'll post an alternative "solution" here today, or tomorrow (GMT+0700).

But, please tell me exactly what Type objects you get when you deserialize the JSON: list of ? array of ? ... or ?

cheers, Bill

Since you stated in your reply to Original Griff that you cannot change the design, here's what I'd do using the classes as you described:
C#
class Artist
{
    String ArtistName {get;set;}
}
 
class Albums
{
    String ArtistName {get;set;}
    String AlbumName {get;set;}
}

Assuming the names of the variables of the two Lists are:
AllAlbums and AllArtists
Then, to delete the Artists for which there are no albums:
C#
HashSet<string> AlbumArtistSet = new HashSet<string>(AllAlbums.Select(al => al.ArtistName));
var trimmedArtists = AllArtists.Where(a => AlbumArtistSet.Contains(a.ArtistName)); // .ToList() if necessary

This makes only one pass through each list.

=================
Edit: MTH
Since the data is being reparsed from JSon, why not reparse it into more useful data structures along the line of what Original Griff proposed?
Or, if you aren't using a DB yourself, then why not setup something like:
C#
// Still assuming the same AllAlbums and AllArtists as above.
// (Shouldn't the Albums class be named Album since it represents ONE album?)
Dictionary<string, List<Albums>> AlbumsByArtistName = new Dictionary<string, List<Albums>>();

// Now populate the dictionary lists.
foreach (var al in AllAlbums)
{
  string name = al.ArtistName;
  List<Albums> albums;
  if (!AlbumsByArtistName.TryGetValue(name, out albums)
  {
    albums = new List<Albums>();
    AlbumsByArtistName.Add(name, albums);
  }
  albums.Add(al);
}
// Now to "trim" the AllArtists list you can:
var trimmedArtists = AllArtists.Where(a => AlbumsByArtistName.Contains(a.ArtistName)); // .ToList() if necessary

Still only one pass through each collection, but now you can access the subset collection of albums by artist name. You can setup similar dictionaries for other properties that you might want subset access. Just remember to add and delete everywhere appropriately.
At this point you've probably noticed that this is looking a bit like a DB. :-)
Using your own in-process (in-memory?) DB, independent from the data source, might be the best solution.
 
Share this answer
 
v2
Comments
pkfox 3-Dec-15 13:06pm    
Thanks Matt that's what I'll do until I can talk to the original dev
BillWoodruff 4-Dec-15 2:19am    
+5 a useful contribution !
pkfox 4-Dec-15 3:12am    
I will give that a go Matt thanks
To be honest, I wouldn't.
Instead of keeping the ArtistName in two places, I'd change the design slightly:
C#
class Artist
    {
    public String ArtistName { get; set; }
    }

class Album
    {
    public Artist Artist { get; set; }
    public String AlbumName { get; set; }
    }

Which would be more like what you would do in a DB.
Then it's trivial:
C#
            List<Artist> artists = new List<Artist>();
            Artist joe = new Artist() { ArtistName = "Joe" };
            Artist mike = new Artist() { ArtistName = "Mike" };
            Artist sally = new Artist() { ArtistName = "Sally" };
            artists.Add(joe);
            artists.Add(mike);
            artists.Add(sally);
            List<Album> albums = new List<Album>();
            albums.Add(new Album() {Artist = mike, AlbumName = "A1"});
//
            var lessArtists = artists.Except(albums.Select(a => a.Artist).Distinct());
 
Share this answer
 
v2
Comments
pkfox 3-Dec-15 12:40pm    
Hi OG unfortunately it's not my design but thanks anyway
OriginalGriff 3-Dec-15 12:49pm    
Trouble is that if you keep that design, you are duplicating the artist name and you can't easily compare Artists - you have to actually compare the names which is a value comparison rather than a (much quicker) reference comparison, and it takes much, much more space. If you think how many albums a single band can have produced (and Nana Mouskouri has over 450) you will be duplicating the name for each of them! You wouldn't do that in a DB - you'd use an artist table and a foreign key - so why do it in your code which presumably has a DB behind it? :laugh:
pkfox 3-Dec-15 13:08pm    
I agree totally but the data is coming from a web server as JSon and I have to map it to these existing classes - I hate web work 😑

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900