Holdings challange 1 & 2

Hi,

I must thank mbspears for some of the code especially the NSIndexSet, I first had to go through the array using an IF statement to only get the top 3 stocks and after reading mbspears code I change the IF statement.

Methods in BNRPortfolio:

-(NSArray *) topThreeHoldings { NSMutableArray *top3Holdings = [_holdings mutableCopy]; // vid value in dollars NSSortDescriptor *vid =[NSSortDescriptor sortDescriptorWithKey:@"valueInDollars" ascending:NO]; [top3Holdings sortUsingDescriptors:@[vid]]; // array of first three NSIndexSet *top3 = [NSIndexSet indexSetWithIndexesInRange:NSMakeRange(0, 3)]; return [top3Holdings objectsAtIndexes:top3]; } -(NSArray *) portfolioAlphabetical { NSMutableArray *anAlphabeticalArray = [_holdings mutableCopy]; // sortAlpha to sort alphabetically NSSortDescriptor *sortAlpha = [NSSortDescriptor sortDescriptorWithKey:@"symbol" ascending:YES]; [anAlphabeticalArray sortUsingDescriptors:@[sortAlpha]]; return anAlphabeticalArray; }

Main:

[code] // print top 3 holdings
NSLog(@“Top three stocks in value within the portfolio”);
NSArray *top3holdings = [[NSArray alloc] init];
top3holdings = [portfolio topThreeHoldings];
for (BNRStockHolding *astock in top3holdings) {
NSLog(@“Stock symbole:%@\tTotal Cost:%.2f\tTotal Value:%.2f”, astock.symbol, astock.costInDollars, astock.valueInDollars);
}

    // sort portfolio alphabetically
    NSLog(@"\n");
    NSLog(@"Sort portfolio alphabetically");
    NSArray *PortAlpha = [[NSArray alloc] init];
    PortAlpha = [portfolio portfolioAlphabetical];
    for (BNRStockHolding *astock in PortAlpha) {
        NSLog(@"Stock symbole:%@\tTotal Cost:$%.2f\tTotal Value:$%.2f", astock.symbol, astock.costInDollars, astock.valueInDollars);
    }[/code]

Here is my solution:

BNRPortfolio.h

[code]- (NSArray *)mostValuableHoldings;

  • (NSArray *)holdingsSortedBySymbol;[/code]

BNRPortfolio.m

[code]- (NSArray *)mostValuableHoldings
{
NSSortDescriptor *vid = [NSSortDescriptor sortDescriptorWithKey:@“valueInDollars” ascending:NO];
NSMutableArray *sortedArray = [[NSMutableArray alloc] init];
sortedArray = _holdings;
[sortedArray sortUsingDescriptors:@[vid]];

return @[sortedArray[0], sortedArray[1], sortedArray[2]];

}

  • (NSArray *)holdingsSortedBySymbol
    {
    NSSortDescriptor *s = [NSSortDescriptor sortDescriptorWithKey:@“symbol” ascending:YES];
    NSMutableArray *sortedArray = [[NSMutableArray alloc] init];
    sortedArray = _holdings;
    [sortedArray sortUsingDescriptors:@[s]];

    return sortedArray;
    }[/code]

main.m

NSLog(@"Top 3 most valuable holdings: %@", [myPortfolio mostValuableHoldings]); NSLog(@"Holdings sorted by symbol: %@", [myPortfolio holdingsSortedBySymbol]);

Open to thoughts…

BNRPortfolio.h

- (NSArray *)topHoldings;
- (NSArray *)abcList;

BNRPortfolio.m

[code]

  • (NSArray *)topHoldings
    {
    NSSortDescriptor *vid = [NSSortDescriptor sortDescriptorWithKey:@“valueInDollars” ascending:NO];
    [_holdings sortUsingDescriptors:@[vid]];
    if (_holdings.count < 3) {
    return _holdings;
    }
    NSArray *top3 = [NSArray arrayWithObjects:[_holdings objectAtIndex:0], [_holdings objectAtIndex:1], [_holdings objectAtIndex:2], nil];
    return top3;
    }

  • (NSArray *)abcList
    {
    NSSortDescriptor *abc = [NSSortDescriptor sortDescriptorWithKey:@“stockName” ascending:YES];
    [_holdings sortUsingDescriptors:@[abc]];
    return _holdings;
    }[/code]

I ended up including an if statement, because when I created my portfolio I was toying with only including some of the stocks instead of everything.

main.m

[code]
NSLog(@“Value of my portfolio is %f”, [myPortfolio portfolioValue]);

    NSLog(@"The top three performing stocks are %@:", [[myPortfolio topHoldings] valueForKey:@"stockName"]);
    
    NSLog(@"The holdings in aphabetical order are: %@", [[myPortfolio abcList] valueForKey:@"stockName"]);[/code]

Hey Losha2u, looks very similar to what I wrote with a few exceptions. Your topHoldings and abcList methods end up actually modifying your _holdings property and returning a direct reference to itself. Instead, similar to the holdings getter method, it should probably send a copy of the _holdings array. For instance, here is my solution which uses the NSArray method sortedArrayUsingDescriptors which ends up returning an immutable copy of the _holdings array:

[code]- (NSArray *)topHoldings {

// Create a copy of the holdings array, sorted by value in dollars descending
NSSortDescriptor *sortByValue = [[NSSortDescriptor alloc] initWithKey:@"valueInDollars" ascending:NO];
NSArray *topholdings = [_holdings sortedArrayUsingDescriptors:@[sortByValue]];

// Return an array with a max of 3 objects
if ([topholdings count] > 3) {
    NSIndexSet *firstThree = [NSIndexSet indexSetWithIndexesInRange:NSMakeRange(0, 3)];
    return [topholdings objectsAtIndexes:firstThree];
}

return topholdings;

}[/code]

- (NSArray *)alphabeticalHoldings { NSSortDescriptor *sortBySymbol = [[NSSortDescriptor alloc] initWithKey:@"symbol" ascending:YES]; return [_holdings sortedArrayUsingDescriptors:@[sortBySymbol]]; }

This way, in my main when I run the topHoldings and alphabeticalHoldings methods they don’t actually modify the holdings property. Also, open to suggestions…

Could somebody help me out please?

When I run my program for the top 3 holdings, it prints out the addresses rather than the value of ‘valueInDollars’

- (NSArray *)topHoldings
{
    NSMutableArray *top3 = _stock;
    NSSortDescriptor *vid = [NSSortDescriptor sortDescriptorWithKey:@"valueInDollars" ascending:NO];
    [top3 sortUsingDescriptors:@[vid]];
    return top3;
}

I hadn’t sorted the array into the top 3 just yet as i wanted to print out the values for all stocks in the portfolio, to check my progress.
I’m not sure the mistake is in my method, any help is appreciated.
Thanks

i have a problem accessing portfolio.h, it is imported at the top of main, but I cannot access totalValue, topHoldings and abcList. When I do this:

I get an error “No visible @interface for NSMutableArray declares the selector topHoldings”.

The same is true for abcList and totalValue from an earlier challenge. Any idea where my mistake could be?

If I need to provide more information, pls let me know. I am pretty new to this and have no prior programming experience.

[quote]NSLog(@"The top 3 are: %@", [portfolio topHoldings]); get an error “No visible @interface for NSMutableArray declares the selector topHoldings”.[/quote]
What is the type of the portfolio variable?

I don’t have the 2nd Edition of the book, but looks like you are sending the topHoldings message to an instance of NSMutableArray. You need to send the message to an instance of the class (I am guessing it is the BNRPortfolio class) that declares the topHoldings method.

yup, that was it. Many thanks!

Hello all,

Here is my solution (Detailed comments or improvements will be appreciated):

BNRPortFolio.m

- (NSArray *)top3MostValuableStock
{

    // Create a sortDescriptor by current value in dolars ascendant
    NSSortDescriptor *byValue = [NSSortDescriptor sortDescriptorWithKey:@"valueInDollars" 
                                             ascending: NO]; // if YES it starts from 0.00 which is not the most valuable ;-)
    NSArray *sortedArray = [(NSArray *)_holdings sortedArrayUsingDescriptors: @[byValue]]; // Casting the mutable array to an immutable one

    // To make sure that it did the work
    NSLog(@"\n\nHere is the sorted PortFolio:");
    for (BNRStockHolding *s in sortedArray) {
        NSLog(@"%@ valued at $%.2f", s.symbol, [s valueInDollars]);
    }
    // Return an array of the 1st 3 members of the sorted array
    NSIndexSet *onlyThe3First = [NSIndexSet indexSetWithIndexesInRange:NSMakeRange(0, 3)]; // NSIndex is better than a whole loop into the array
    return [sortedArray objectsAtIndexes:onlyThe3First];

}

- (NSArray *)alphabeticSortOfStockSymbol
{
    // Create a sortDescriptor by current value in dolars ascendant
    NSSortDescriptor *alphaB = [NSSortDescriptor sortDescriptorWithKey:@"symbol"
                                                              ascending: YES
                                selector:@selector(caseInsensitiveCompare:)]; // Isn't it better to be cautious for the user ? Then the comparison must be case insensitive
    NSArray *sortedArray = [(NSArray *)_holdings sortedArrayUsingDescriptors: @[alphaB]];
    return sortedArray;
    
}

I prefer to cast the mutable array into an immutable one has it only permits read access.

and main.m


        NSArray *theBestStock = myPortFolio.top3MostValuableStock;
        NSLog(@"\n\nThe 1st 3 in the PortFolio are :");
        for (BNRForeignStockHolding *tbf in theBestStock) {
            NSLog(@"%@ valued at $%.2f", tbf.symbol, [tbf valueInDollars]);
        }
        NSLog(@"\n\nAhabetical sort of the PortFolio : ");
        NSArray *alphaBStock = myPortFolio.alphabeticSortOfStockSymbol;
        for (BNRForeignStockHolding *alphab in alphaBStock) {
            NSLog(@"%@ valued at $%.2f", alphab.symbol, [alphab valueInDollars]);
        }

The result is:

2014-03-26 04:54:48.112 ChallengeChapter21[1229:303] 

The TOTAL cost is 6656.00$, the TOTAL value is 3281.68$ so the result is -92.64$
2014-03-26 04:54:48.121 ChallengeChapter21[1229:303] 

Here is the sorted PortFolio:
2014-03-26 04:54:48.122 ChallengeChapter21[1229:303] LMN valued at $1699.20
2014-03-26 04:54:48.123 ChallengeChapter21[1229:303] LZH valued at $1214.08
2014-03-26 04:54:48.124 ChallengeChapter21[1229:303] CGY valued at $368.40
2014-03-26 04:54:48.125 ChallengeChapter21[1229:303] XYZ valued at $0.00
2014-03-26 04:54:48.125 ChallengeChapter21[1229:303] ABC valued at $0.00
2014-03-26 04:54:48.126 ChallengeChapter21[1229:303] 

Top 3 in the PortFolio
2014-03-26 04:54:48.131 ChallengeChapter21[1229:303] LMN valued at $1699.20
2014-03-26 04:54:48.133 ChallengeChapter21[1229:303] LZH valued at $1214.08
2014-03-26 04:54:48.134 ChallengeChapter21[1229:303] CGY valued at $368.40
2014-03-26 04:54:48.136 ChallengeChapter21[1229:303] 

Ahabetical sort of PortFolio
2014-03-26 04:54:48.137 ChallengeChapter21[1229:303] ABC valued at $0.00
2014-03-26 04:54:48.138 ChallengeChapter21[1229:303] CGY valued at $368.40
2014-03-26 04:54:48.140 ChallengeChapter21[1229:303] LMN valued at $1699.20
2014-03-26 04:54:48.141 ChallengeChapter21[1229:303] LZH valued at $1214.08
2014-03-26 04:54:48.144 ChallengeChapter21[1229:303] XYZ valued at $0.00

can someone explain me why in the main.m file in the for loop declaring the array to be BNRForeignStockHolding or BNRStockHolding does not make any difference in the results?

Thanks

What is everyone declaring setters and getters with this challenge instead of using @properties?

I enjoyed this challenge, though admittedly I had to look on these forums for help with the “NSIndexSet” bit.

[code]// BNRPortfolio.h

@property (nonatomic, copy) NSArray *topThree;
@property (nonatomic, copy) NSArray *alpha;[/code]

[code]// BNRPortfolio.m

  • (NSArray *)topThree {
    // sort array by valueInDollars
    NSSortDescriptor *vid = [NSSortDescriptor sortDescriptorWithKey:@"valueInDollars"
    ascending:NO];
    // apply sort descriptors
    [_stockHoldings sortUsingDescriptors:@[vid]];

    // check size of array
    if (_stockHoldings.count > 3) {
    // create index set for 3 indexes
    NSIndexSet *top3 = [NSIndexSet indexSetWithIndexesInRange:NSMakeRange(0, 3)];
    // return array with index set (only if test is true)
    return [_stockHoldings objectsAtIndexes:top3];
    }

    // else, return sorted array if previous test fails (i.e. if array is has less than 3 objects)
    return _stockHoldings;
    }

  • (NSArray *)alpha {
    // sort by symbol
    NSSortDescriptor *sym = [NSSortDescriptor sortDescriptorWithKey:@"symbol"
    ascending:YES];
    //apply sort descriptor
    [_stockHoldings sortUsingDescriptors:@[sym]];

    // return sorted array
    return _stockHoldings;
    }[/code]

[code]// main.m

    // log returned value from topThree method in portfolio class object
    NSLog(@"Top 3 holdings: %@", portfolio.topThree);
    
    // log returned value from alpha method  
    NSLog(@"Sorted holdings: %@", portfolio.alpha);[/code]

[quote=“ibex10”][quote]NSLog(@"The top 3 are: %@", [portfolio topHoldings]); get an error “No visible @interface for NSMutableArray declares the selector topHoldings”.[/quote]
What is the type of the portfolio variable?

I don’t have the 2nd Edition of the book, but looks like you are sending the topHoldings message to an instance of NSMutableArray. You need to send the message to an instance of the class (I am guessing it is the BNRPortfolio class) that declares the topHoldings method.[/quote]

I’m getting the “No known class” error message from the compiler. According to the code, I should be sending the NSLog to BNRPortfolio methods mostValuableHoldings and holdingsSortedBySymbol but it looks like it is being sent to an NSArray. Can someone help? I’ve been trying to get this to work for hours.

//
// BNRPortfolio.h
// Stocks
//
// Created by Nelson Capes on 7/31/15.
// Copyright © 2015 Big Nerd Ranch. All rights reserved.
//

#import <Foundation/Foundation.h>
#import “BNRStockHolding.h”
#import “BNRForeignStockHolding.h”
@class BNRStockHolding;

@interface BNRPortfolio : NSObject
{
NSMutableArray *_holdings;

}

-(void)setHolding: (NSMutableArray *)a;
-(void)addHolding:(NSMutableArray *)a;
-(NSArray *)mostValuableHoldings;
-(NSArray *)holdingsSortedBySymbol;

@end
//
// BNRPortfolio.m
// Stocks
//
// Created by Nelson Capes on 7/31/15.
// Copyright © 2015 Big Nerd Ranch. All rights reserved.
//

#import “BNRPortfolio.h”
#import “BNRStockHolding.h”
#import “BNRForeignStockHolding.h”

@implementation BNRPortfolio

-(void)addHolding: (NSMutableArray *)h
{
if(!_holdings){
_holdings = [[NSMutableArray alloc] init];
}
[_holdings addObject:h];
}

-(void)setHolding:(NSMutableArray *)h
{
_holdings = [h mutableCopy];
}

-(NSMutableArray *)holdings
{
return [_holdings copy];
}

  • (NSArray *)mostValuableHoldings
    {
    NSSortDescriptor *vid = [NSSortDescriptor sortDescriptorWithKey:@“valueInDollars” ascending:NO];
    NSMutableArray *sortedArray = [[NSMutableArray alloc] init];
    sortedArray = _holdings;
    [sortedArray sortUsingDescriptors:@[vid]];

    return @[sortedArray[0], sortedArray[1], sortedArray[2]];
    }

  • (NSArray *)holdingsSortedBySymbol
    {
    NSSortDescriptor *s = [NSSortDescriptor sortDescriptorWithKey:@“symbol” ascending:YES];
    NSMutableArray *sortedArray = [[NSMutableArray alloc] init];
    sortedArray = _holdings;
    [sortedArray sortUsingDescriptors:@[s]];

    return sortedArray;
    }

@end

//
// main.m
// Stocks
//
// Created by Nelson Capes on 7/28/15.
// Copyright © 2015 Big Nerd Ranch. All rights reserved.
//

#import <Foundation/Foundation.h>
#import “BNRStockHolding.h”
#import “BNRForeignStockHolding.h”
#import “BNRSymbol.h”
#import “BNRPortfolio.h”
@class BNRPortfolio;

int main(int argc, const char * argv[]) {
@autoreleasepool {

    NSMutableArray *holdings =[[NSMutableArray alloc]init];
    
    BNRStockHolding *stock1 = [[BNRStockHolding alloc]init];
    BNRStockHolding *stock2 = [[BNRStockHolding alloc] init];
    BNRForeignStockHolding *stock3 = [[BNRForeignStockHolding alloc] init];
    
    
    
    [holdings addObject:stock1];
    [holdings addObject:stock2];
    [holdings addObject:stock3];
       
    stock1.purchaseSharePrice = 2.30;
    stock1.currentSharePrice = 4.50;
    stock1.numberOfShares = 40;
    
    stock2.purchaseSharePrice = 2.30;
    stock2.currentSharePrice = 4.50;
    stock2.numberOfShares = 40;
    
    stock3.purchaseSharePrice = 2.30;
    stock3.currentSharePrice = 4.50;
    stock3.numberOfShares = 40;
    stock3.conversionRate = 0.94;
    
    stock1.symbol = @"@XYZ";
    stock2.symbol =@"@ABC";
    stock3.symbol = @"@LMN";
    
    
    
    NSLog(@"Top 3 most valuable holdings: %@", [BNRPortfolio mostValuableHoldings]);
    NSLog(@"Holdings sorted by symbol: %@", [BNRPortfolio holdingsSortedBySymbol]);

    
}
return 0;

[quote=“nrcapes”][quote=“ibex10”][quote]NSLog(@"The top 3 are: %@", [portfolio topHoldings]); get an error “No visible @interface for NSMutableArray declares the selector topHoldings”.[/quote]
What is the type of the portfolio variable?

I don’t have the 2nd Edition of the book, but looks like you are sending the topHoldings message to an instance of NSMutableArray. You need to send the message to an instance of the class (I am guessing it is the BNRPortfolio class) that declares the topHoldings method.[/quote]
PLEASE DISREGARD the following. I realized I did not create an instance of the BNRPortfolio class, so the message was going to a class that did not have a method. I think the Challenge could be a little more helpful.
I’m getting the “No known class” error message from the compiler. According to the code, I should be sending the NSLog to BNRPortfolio methods mostValuableHoldings and holdingsSortedBySymbol but it looks like it is being sent to an NSArray. Can someone help? I’ve been trying to get this to work for hours.

//
// BNRPortfolio.h
// Stocks
//
// Created by Nelson Capes on 7/31/15.
// Copyright © 2015 Big Nerd Ranch. All rights reserved.
//

#import <Foundation/Foundation.h>
#import “BNRStockHolding.h”
#import “BNRForeignStockHolding.h”
@class BNRStockHolding;

@interface BNRPortfolio : NSObject
{
NSMutableArray *_holdings;

}

-(void)setHolding: (NSMutableArray *)a;
-(void)addHolding:(NSMutableArray *)a;
-(NSArray *)mostValuableHoldings;
-(NSArray *)holdingsSortedBySymbol;

@end
//
// BNRPortfolio.m
// Stocks
//
// Created by Nelson Capes on 7/31/15.
// Copyright © 2015 Big Nerd Ranch. All rights reserved.
//

#import “BNRPortfolio.h”
#import “BNRStockHolding.h”
#import “BNRForeignStockHolding.h”

@implementation BNRPortfolio

-(void)addHolding: (NSMutableArray *)h
{
if(!_holdings){
_holdings = [[NSMutableArray alloc] init];
}
[_holdings addObject:h];
}

-(void)setHolding:(NSMutableArray *)h
{
_holdings = [h mutableCopy];
}

-(NSMutableArray *)holdings
{
return [_holdings copy];
}

  • (NSArray *)mostValuableHoldings
    {
    NSSortDescriptor *vid = [NSSortDescriptor sortDescriptorWithKey:@“valueInDollars” ascending:NO];
    NSMutableArray *sortedArray = [[NSMutableArray alloc] init];
    sortedArray = _holdings;
    [sortedArray sortUsingDescriptors:@[vid]];

    return @[sortedArray[0], sortedArray[1], sortedArray[2]];
    }

  • (NSArray *)holdingsSortedBySymbol
    {
    NSSortDescriptor *s = [NSSortDescriptor sortDescriptorWithKey:@“symbol” ascending:YES];
    NSMutableArray *sortedArray = [[NSMutableArray alloc] init];
    sortedArray = _holdings;
    [sortedArray sortUsingDescriptors:@[s]];

    return sortedArray;
    }

@end

//
// main.m
// Stocks
//
// Created by Nelson Capes on 7/28/15.
// Copyright © 2015 Big Nerd Ranch. All rights reserved.
//

#import <Foundation/Foundation.h>
#import “BNRStockHolding.h”
#import “BNRForeignStockHolding.h”
#import “BNRSymbol.h”
#import “BNRPortfolio.h”
@class BNRPortfolio;

int main(int argc, const char * argv[]) {
@autoreleasepool {

    NSMutableArray *holdings =[[NSMutableArray alloc]init];
    
    BNRStockHolding *stock1 = [[BNRStockHolding alloc]init];
    BNRStockHolding *stock2 = [[BNRStockHolding alloc] init];
    BNRForeignStockHolding *stock3 = [[BNRForeignStockHolding alloc] init];
    
    
    
    [holdings addObject:stock1];
    [holdings addObject:stock2];
    [holdings addObject:stock3];
       
    stock1.purchaseSharePrice = 2.30;
    stock1.currentSharePrice = 4.50;
    stock1.numberOfShares = 40;
    
    stock2.purchaseSharePrice = 2.30;
    stock2.currentSharePrice = 4.50;
    stock2.numberOfShares = 40;
    
    stock3.purchaseSharePrice = 2.30;
    stock3.currentSharePrice = 4.50;
    stock3.numberOfShares = 40;
    stock3.conversionRate = 0.94;
    
    stock1.symbol = @"@XYZ";
    stock2.symbol =@"@ABC";
    stock3.symbol = @"@LMN";
    
    
    
    NSLog(@"Top 3 most valuable holdings: %@", [BNRPortfolio mostValuableHoldings]);
    NSLog(@"Holdings sorted by symbol: %@", [BNRPortfolio holdingsSortedBySymbol]);

    
}
return 0;[/quote]