2

So I have an struct

struct car{
   string ownerName;
   float price;
   int year;
};

and I declared an array of these structs car *cars = new car[1000] Each car has an index, for example, the car with index 0 has name John Smith.

So, my question is knowing the name of the owner how do I access the index of the car. I know that the other way i would write cars[0].name, to get the name, but how would i do it backwards?

Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
user2775084
  • 95
  • 1
  • 4
  • 11
  • 2
    You'd use an associative array type, spelled `std::map`, to map a string to an array index. It would be a second data structure, parallel to but separate from, the main array of cars. You might use a pointer instead of the `size_t` if you preferred. – Jonathan Leffler Sep 16 '13 at 05:18
  • okay ! thank you ! I didn't know about that array type. – user2775084 Sep 16 '13 at 05:24

2 Answers2

3

Two possible ways come to my mind. One is writing a function that finds index by name.

#include <string>    
using namespace std;

car *find_by_name(car* cars, const string& name, int from, int to) {
    car* car_ptr = NULL;
    for(int i = from; i < to; i++) {
        if (cars[i].ownerName == name) {
            car_ptr = cars+i;
            break;
        }
    }
    return car_ptr;
}

As you may notice, this function is very expensive (O(n)). The other one and the easiest one, in my opinion, is using Map or HashMap to do so.

#include <map>
#include <string>
#include <iostream>
using namespace std;

car set_new_val(map<string, car*>& my_map, const string& name, const float price, const int year) {
    car* car_heap = new car();
    car_heap->ownerName = name;
    car_heap->price = price;
    car_hep->year = year;
    my_map.insert(pair<string, car*>(name, car_heap));
}

car* find_car_by_name(const map<string, car*>& my_map, const string& name) {
    map<string, car*>::iterator it;

    if ((it = my_map.find(name)) == my_map.end())
        return NULL;
    return it->second;
}

int main(int argc, char* argv[]) {
    map<string, car*> my_cars_data;
    set_new_val(my_cars_data, "James", 2233000.5, 2013);
    set_new_val(my_cars_data, "Dave", 1222000.5, 2011);
    set_new_val(my_cars_data, "Aaron", 1222000.75, 2012);

    car* james_car = find_car_by_name(my_cars_data, "James");
    cout << "Year " << james_car->year << endl;
    car* null_car = find_car_by_name(my_cars_data, "Santa");
    if (null_car == NULL)
        cout << "No owner with the name Santa is recorded" << endl;
    ...
    ...

    free_map(my_map);
    return 0;

According to C++11, lookup for a key using Map takes O(lgn) (HashMap is O(1)), for more details read here . That's a big pro, if you handle mass of data (not to mention that it is easier to maintain).

Community
  • 1
  • 1
boaz_shuster
  • 2,825
  • 20
  • 26
0

If you use a sequential container (array, vector...) you have to search for the name. In an unsorted array a linear search is required.

// linear search

string name = "joe";
auto it = find_if(begin(cars), end(cars), 
    [&name](const car& c) { return c.ownerName == name; });

auto index = it - begin(cars);

If you have performance problems with this approach you could sort the array and use a binary search (preferable if your array of cars does not change) or use a associative container which gives you fast access to an element by key (map, multi_map, unordered_map...)

// binary search

struct {
    bool operator()(const car& lh, const car& rh) { return lh.ownerName < rh.ownerName; };
    bool operator()(const car& lh, const std::string& rh) { return lh.ownerName < rh; };
    bool operator()(const std::string& lh, const car& rh) { return lh < rh.ownerName; };

} byName;

sort(begin(cars), end(cars), byName);
auto it2 = lower_bound(begin(cars), end(cars), name, byName);
if (it != end(cars) && it->ownerName == name)
{
    auto index2 = it - begin(cars);
}
hansmaad
  • 18,417
  • 9
  • 53
  • 94