3

The API provides methods to sort and filter individual questions by favorite count.

In order to calculate the question favorite count totals per User, some grouping and set operations are required.

e.g.

total_views display_name [user_id]
------------------------------------------
1000 John Doe [12]
900 Joe Snow [431]
. . . etc etc

Post your solution to this use case in the language/library syntax of your choice.

3 Answers 3

2

JavaSript / Soapi.JS


using Soapi.JS


Soapi.RouteFactory("api.stackapps.com", apiKey) // get all users
.Questions({ pagesize: 100 }).getPagedResponse(function(data) {

    var values = {}, keys = [];
    // add up the favorite for each user
    for (var i = 0; i < data.items.length; i++) {
        var q = data.items[i];
        var u = q.owner;
        if (u) {
            if (!values[u.user_id]) {
                keys.push(u.user_id);
                values[u.user_id] = {
                    display_name: u.display_name,
                    favorite_count: 0
                };
            }
            values[u.user_id].favorite_count += q.favorite_count;
        }
    }

    // sort and dump
    var output = "";
    for (var i = 0; i < keys.sort(function(a, b) {
        return values[b].favorite_count - values[a].favorite_count;
    }).length; i++) {
        output += values[keys[i]].favorite_count + " " + values[keys[i]].display_name + "\r\n";
    }

    document.getElementById("output").innerHTML = output;

});
   

Output:

100 Kevin Montrose
88 George Edison
81 code poet
28 Soviut
27 lfoust
22 Adam Wright
22 systempuntoout
21 S.Mark
20 Felix
17 Farseeker
16 Dave DeLong
11 Dave Swersky
10 Bill the Lizard
9 Matt S.
9 Franci Penov
8 Jeff Atwood
8 Edan Maor
7 Jedi Master Spooky
7 codeka
7 carson
7 nabeelmukhtar
7 Shay Erlichmen
7 swanson
6 Steffen Opel
6 Lucas Jones
6 Jason
6 Thomas McDonald
6 Kyle Cronin
6 Joel Potter
5 conmulligan
5 Catchwa
5 Jonathan
5 TheHurt
5 Ricky
5 SztupY
5 ColinD
5 Mark Rushakoff
4 Adam
4 jjnguy
4 chenyuejie
4 Koning Baard
3 Yacoby
3 phsr
3 Nick Presta
3 Igor Zevaka
3 johnwards
3 blork
3 Robert Munteanu
3 Riduidel
3 InfinitiesLoop
3 Martin Plante
2 tonklon
2 Ryan Brunner
2 Dennis Williamson
2 Soldier.moth
2 eWolf
2 Josh Kelley
2 radius
2 James A. Rosen
2 Kevin
2 RichH
2 Nippysaurus
2 Peter Mortensen
2 John Bristowe
2 Mark Hurd
2 adrianbanks
1 Alexandre Rafalovitch
1 balpha
1 Matt Culbreth
1 mlaw
1 Nathan Reed
1 Nicolas Raoul
1 tsudot
1 Ngu Soon Hui
1 Nathan Voxland
1 Joe
1 Michael B.
1 Shane
1 Frank Krueger
1 Robert Cartaino
1 Charles Stewart
1 svick
1 jmoy
1 Fernando
1 Peter Mourfield
1 pufferfish
1 Artefacto
1 Robert Love
1 iconiK
1 voyager
1 coobird
1 Lucas McCoy
1 Chacha102
1 Matthew Pelser

Requests generated


#   Result  Protocol    Host    URL Body    Caching Content-Type    Process Comments    Custom  
1   200 HTTP    api.stackapps.com   /1.0/questions?key=foo-bar-fu&pagesize=100&page=1&jsonp=Soapi._internal._callback0  14,525  private     application/json; charset=utf-8 iexplore:5676           
2   200 HTTP    api.stackapps.com   /1.0/questions?key=foo-bar-fu&pagesize=100&page=2&jsonp=Soapi._internal._callback1  14,704  private     application/json; charset=utf-8 iexplore:5676           
3   200 HTTP    api.stackapps.com   /1.0/questions?key=foo-bar-fu&pagesize=100&page=3&jsonp=Soapi._internal._callback2  15,407  private     application/json; charset=utf-8 iexplore:5676           
4   200 HTTP    api.stackapps.com   /1.0/questions?key=foo-bar-fu&pagesize=100&page=4&jsonp=Soapi._internal._callback3  14,012  private     application/json; charset=utf-8 iexplore:5676           
5   200 HTTP    api.stackapps.com   /1.0/questions?key=foo-bar-fu&pagesize=100&page=5&jsonp=Soapi._internal._callback4  14,457  private     application/json; charset=utf-8 iexplore:5676           
6   200 HTTP    api.stackapps.com   /1.0/questions?key=foo-bar-fu&pagesize=100&page=6&jsonp=Soapi._internal._callback5  4,234   private     application/json; charset=utf-8 iexplore:5676           
7   200 HTTP    api.stackapps.com   /1.0/questions?key=foo-bar-fu&pagesize=100&page=7&jsonp=Soapi._internal._callback6  204 private     application/json; charset=utf-8 iexplore:5676           

2

C# / Soapi.CS


using Soapi.CS

//

Context
    .Official
    .StackApps
    .Questions
    .PageCount(0)
    .PageSize(100)
    .GroupBy(question => question.OwnerId)
    .Select(group => new
    {
        User = group.First().Owner.DisplayName 
          + "[" + group.First().Owner.UserId + "]",
        FavedCount = group.Sum(question => question.FavoriteCount)
    })
    .OrderByDescending(item => item.FavedCount).ToList()
    .ForEach(item => 
        Console.WriteLine("{0} - {1}", item.FavedCount, item.User));

//

Output:

100 - Kevin Montrose[2]
87 - George Edison[18]
81 - code poet[14]
28 - Soviut[825]
27 - lfoust[11]
22 - Adam Wright[5]
22 - systempuntoout[51]
21 - S.Mark[40]
20 - Felix[956]
17 - Farseeker[816]
16 - Dave DeLong[448]
11 - Dave Swersky[29]
10 - Bill the Lizard[9]
9 - Matt S.[30]
9 - Franci Penov[13]
8 - Jeff Atwood[4]
8 - Edan Maor[1241]
7 - Jedi Master Spooky[192]
7 - codeka[1290]
7 - carson[33]
7 - nabeelmukhtar[1026]
7 - Shay Erlichmen[614]
7 - swanson[839]
6 - Steffen Opel[377]
6 - Lucas Jones[570]
6 - Kyle Cronin[42]
6 - Joel Potter[8]
6 - Jason[19]
6 - Thomas McDonald[1031]
5 - conmulligan[449]
5 - Catchwa[700]
5 - Jonathan[938]
5 - TheHurt[17]
5 - Ricky[199]
5 - SztupY[1265]
5 - ColinD[222]
5 - Mark Rushakoff[1048]
4 - Adam[1395]
4 - jjnguy[39]
4 - chenyuejie[2292]
4 - Koning Baard[451]
3 - Yacoby[1049]
3 - phsr[693]
3 - Nick Presta[186]
3 - Igor Zevaka[113]
3 - johnwards[638]
3 - blork[1849]
3 - Robert Munteanu[358]
3 - Riduidel[2192]
3 - InfinitiesLoop[1394]
3 - Martin Plante[28]
2 - tonklon[2734]
2 - Ryan Brunner[1263]
2 - Dennis Williamson[171]
2 - Soldier.moth[91]
2 - eWolf[664]
2 - Josh Kelley[2287]
2 - radius[295]
2 - James A. Rosen[140]
2 - Kevin[2296]
2 - Peter Mortensen[151]
2 - adrianbanks[127]
2 - RichH[757]
2 - Nippysaurus[1221]
2 - John Bristowe[70]
2 - Mark Hurd[44]
1 - Alexandre Rafalovitch[2883]
1 - balpha[43]
1 - Matt Culbreth[2829]
1 - mlaw[2467]
1 - Nathan Reed[680]
1 - Nicolas Raoul[2679]
1 - tsudot[2662]
1 - Ngu Soon Hui[216]
1 - Nathan Voxland[2442]
1 - Joe[2418]
1 - Michael B.[234]
1 - Chacha102[23]
1 - Matthew Pelser[138]
1 - Shane[1270]
1 - Frank Krueger[2203]
1 - Robert Cartaino[431]
1 - Charles Stewart[2083]
1 - svick[505]
1 - jmoy[1978]
1 - Fernando[1856]
1 - Peter Mourfield[424]
1 - pufferfish[1689]
1 - Artefacto[1179]
1 - Robert Love[1578]
1 - iconiK[375]
1 - voyager[20]
1 - coobird[525]
1 - Lucas McCoy[239]

Not related to the question/answer: these are the requests issued to generate the above results:

#   Result  Protocol    Host    URL Body    Caching Content-Type    Process Comments    Custom  
1   200 HTTP    api.stackapps.com   /1.0/questions?pagesize=100&key=foo-bar-fu  14,697  private     application/json; charset=utf-8 jetbrains.resharper.taskrunner.msil:7276            
2   200 HTTP    api.stackapps.com   /1.0/questions?page=2&pagesize=100&key=foo-bar-fu   14,598  private     application/json; charset=utf-8 jetbrains.resharper.taskrunner.msil:7276            
3   200 HTTP    api.stackapps.com   /1.0/questions?page=3&pagesize=100&key=foo-bar-fu   15,231  private     application/json; charset=utf-8 jetbrains.resharper.taskrunner.msil:7276            
4   200 HTTP    api.stackapps.com   /1.0/questions?page=4&pagesize=100&key=foo-bar-fu   14,022  private     application/json; charset=utf-8 jetbrains.resharper.taskrunner.msil:7276            
5   200 HTTP    api.stackapps.com   /1.0/questions?page=5&pagesize=100&key=foo-bar-fu   14,352  private     application/json; charset=utf-8 jetbrains.resharper.taskrunner.msil:7276            
6   200 HTTP    api.stackapps.com   /1.0/questions?page=6&pagesize=100&key=foo-bar-fu   3,904   private     application/json; charset=utf-8 jetbrains.resharper.taskrunner.msil:7276            

2
  • that's elegant code. Aug 18, 2010 at 11:58
  • @system - thank you. thank you very much.... (tried to find elvis clip but no luck) Aug 18, 2010 at 13:58
2

StackKit (Objective-C)

Objective-C can be a pretty verbose language, especially with how I've chosen to implement the API. That being said, here's how StackKit does this:

SKSite * site = [SKSite stackAppsSite];

//begin building our request for all questions  
SKFetchRequest * request = [[SKFetchRequest alloc] init];
[request setEntity:[SKQuestion class]];

//this will hold how the favorited counts for a user
NSCountedSet * counts = [NSCountedSet set];

NSUInteger count = NSUIntegerMax;
//retrieve all the questions
for (NSUInteger offset = 0; offset < count; offset += 100) {
    //starting from the appropriate offset (page)
    [request setFetchOffset:offset];
    
    NSError * error = nil;
    NSArray * matches = [site executeSynchronousFetchRequest:request error:&error];

    //loop through all the questions and record how many times they've been favorited
    for (SKQuestion * question in matches) {
        NSUInteger count = [[question favoriteCount] unsignedIntegerValue];
        for (int i = 0; i < count; ++i) { [counts addObject:[question ownerID]]; }
    }
    
    if (count == NSUIntegerMax) {
        count = [[request fetchTotal] unsignedIntegerValue];
    }
}
[request release];

//turn the counted set into a dictionary (so we can sort it)
NSMutableArray * favoriteCounts = [NSMutableArray array];
for (id user in counts) {
    [favoriteCounts addObject:[NSDictionary dictionaryWithObjectsAndKeys:
                               user, @"user",
                               [NSNumber numberWithUnsignedInteger:[counts countForObject:user]], @"count",
                               nil]];
}
//sort the dictionary by the count, descending
[favoriteCounts sortUsingDescriptors:[NSArray arrayWithObject:[[[NSSortDescriptor alloc] initWithKey:@"count" ascending:NO] autorelease]]];

//create a request to fetch all the user objects
request = [[SKFetchRequest alloc] init];
[request setEntity:[SKUser class]];
[request setPredicate:[NSPredicate predicateWithFormat:@"%K = %@", SKUserID, [favoriteCounts valueForKey:@"user"]]];

NSArray * users = [site executeSynchronousFetchRequest:request error:nil];
[request release];

//build a userID => user map
NSDictionary * userMapping = [NSDictionary dictionaryWithObjects:users forKeys:[users valueForKey:SKUserID]];

//print out the favorited count and username
for (NSDictionary * top in favoriteCounts) {
    SKUser * user = [userMapping objectForKey:[top objectForKey:@"user"]];
    NSLog(@"%2d - %@ [%@]", [[top objectForKey:@"count"] unsignedIntegerValue], [user displayName], [user userID]);
}

Outputs:

101 - Kevin Montrose [2]
88 - George Edison [18]
86 - code poet [14]
29 - Soviut [825]
28 - lfoust [11]
22 - Adam Wright [5]
22 - systempuntoout [51]
21 - S.Mark [40]
20 - Felix [956]
17 - Farseeker [816]
16 - Dave DeLong [448]
11 - Dave Swersky [29]
10 - Bill the Lizard [9]
 9 - Franci Penov [13]
 9 - Matt S. [30]
 8 - Jeff Atwood [4]
 8 - Edan Maor [1241]
 7 - carson [33]
 7 - swanson [839]
 7 - Jedi Master Spooky [192]
 7 - nabeelmukhtar [1026]
 7 - Shay Erlichmen [614]
 7 - codeka [1290]
 6 - Kyle Cronin [42]
 6 - Jason [19]
 6 - Joel Potter [8]
 6 - Catchwa [700]
 6 - Thomas McDonald [1031]
 6 - Lucas Jones [570]
 6 - Steffen Opel [377]
 5 - SztupY [1265]
 5 - TheHurt [17]
 5 - ColinD [222]
 5 - Ricky [199]
 5 - Jonathan [938]
 5 - conmulligan [449]
 5 - Mark Rushakoff [1048]
 4 - chenyuejie [2292]
 4 - Koning Baard [451]
 4 - jjnguy [39]
 4 - Adam [1395]
 3 - Martin Plante [28]
 3 - Riduidel [2192]
 3 - Yacoby [1049]
 3 - InfinitiesLoop [1394]
 3 - Igor Zevaka [113]
 3 - phsr [693]
 3 - Robert Munteanu [358]
 3 - blork [1849]
 3 - Nick Presta [186]
 3 - johnwards [638]
 2 - John Bristowe [70]
 2 - eWolf [664]
 2 - Soldier.moth [91]
 2 - James A. Rosen [140]
 2 - Nippysaurus [1221]
 2 - Ryan Brunner [1263]
 2 - Dennis Williamson [171]
 2 - adrianbanks [127]
 2 - radius [295]
 2 - Kevin [2296]
 2 - tonklon [2734]
 2 - Peter Mortensen [151]
 2 - Josh Kelley [2287]
 2 - Mark Hurd [44]
 2 - RichH [757]
 1 - iconiK [375]
 1 - Peter Mourfield [424]
 1 - Robert Cartaino [431]
 1 - Joe [2418]
 1 - pufferfish [1689]
 1 - mlaw [2467]
 1 - Nicolas Raoul [2679]
 1 - Artefacto [1179]
 1 - jmoy [1978]
 1 - Shane [1270]
 1 - Matthew Pelser [138]
 1 - Charles Stewart [2083]
 1 - coobird [525]
 1 - Nathan Voxland [2442]
 1 - Michael B. [234]
 1 - Robert Love [1578]
 1 - balpha [43]
 1 - Matt Culbreth [2829]
 1 - voyager [20]
 1 - Lucas McCoy [239]
 1 - Alexandre Rafalovitch [2883]
 1 - Ngu Soon Hui [216]
 1 - Frank Krueger [2203]
 1 - svick [505]
 1 - Fernando [1856]
 1 - tsudot [2662]
 1 - Chacha102 [23]
 1 - Nathan Reed [680]

Calls made:

http://api.stackapps.com/1.0/questions?body=true&key=<key>&pagesize=100&page=1
http://api.stackapps.com/1.0/questions?body=true&key=<key>&pagesize=100&page=2
http://api.stackapps.com/1.0/questions?body=true&key=<key>&pagesize=100&page=3
http://api.stackapps.com/1.0/questions?body=true&key=<key>&pagesize=100&page=4
http://api.stackapps.com/1.0/questions?body=true&key=<key>&pagesize=100&page=5
http://api.stackapps.com/1.0/questions?body=true&key=<key>&pagesize=100&page=6
http://api.stackapps.com/1.0/users/2;18;14;825;11;5;51;40;956;816;448;29;9;13;30;4;1241;33;839;192;1026;614;1290;42;19;8;700;1031;570;377;1265;17;222;199;938;449;1048;2292;451;39;1395;28;2192;1049;1394;113;693;358;1849;186;638;70;664;91;140;1221;1263;171;127;295;2296;2734;151;2287;44;757;375;424;431;2418;1689;2467;2679;1179;1978;1270;138;2083;525;2442;234;1578;43;2829;20;239;2883;216;2203;505;1856;2662;23;680?key=<key>&page=1&pagesize=100
3
  • thanks dave. it is very interesting to see implementations of familiar code in other lanquages/libraries, kinda like a rosetta stone of sorts. Aug 18, 2010 at 2:12
  • @code poet yeah, definitely. one of the design decisions i made w/ my wrapper is that a request only returns data of a single type. so even though requesting a question returns user information, i only return the question info itself. that means that i have to do the extra request at the end for all the user info, but also means i don't have partially created User objects floating around. Aug 18, 2010 at 14:20
  • sound decision. I took another approach: all api objects are 'stubs' by default. If the query in question returns full objects, i clear the IsStub flag, recursively. Subsequently, upon first access, if a stub and lazy loading is enabled on the context, the object is fetched. In some cases this can add up to a lot of requests, so the context has an eager loading option, wherein when a page of objects are retrieved, all of the stubs are fetched in a single batch, so a request for a page of 100 questions (w body/answers/comments) would result in 2 requests and return all the data. Aug 18, 2010 at 15:01

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .