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.

Steffen Opel
  • 1,380
  • 8
  • 14
Sky Sanders
  • 12,068
  • 3
  • 31
  • 60

3 Answers3

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

Sky Sanders
  • 12,068
  • 3
  • 31
  • 60
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

Sky Sanders
  • 12,068
  • 3
  • 31
  • 60
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:&amp;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 &lt; 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
Dave DeLong
  • 5,264
  • 1
  • 16
  • 12
  • thanks dave. it is very interesting to see implementations of familiar code in other lanquages/libraries, kinda like a rosetta stone of sorts. – Sky Sanders Aug 18 '10 at 02: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. – Dave DeLong Aug 18 '10 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. – Sky Sanders Aug 18 '10 at 15:01