Size of largest string in vector

I'm wondering if there is a better way to get the size of the largest string in a vector without using loops and if there are there any general imporvement I can make in this code?

1
2
3
4
5
6
auto largest_element{max_element(text.begin(), text.end(),
                                 [](string const& lhs, string const& rhs)
                                 {
                                      return lhs.size() < rhs.size();
                                 })};
long unsigned int base_width{largest_element->size()};
Last edited on
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#include <algorithm> // std::max_element
                     // https://en.cppreference.com/w/cpp/algorithm/max_element
#include <iostream>
#include <vector>
#include <string>

static bool str_compare(std::string a, std::string b)
{
   return (a.size() < b.size());
}

int main()
{
   std::vector<std::string> v { "a", "bbbbb", "cc", "ddd", "eeee" };
   
   auto result {  std::max_element(v.begin(), v.end(), str_compare) };
   
   auto elem { std::distance(v.begin(), result) };
   
   std::cout << "max element at: " << elem << '\n';
   std::cout << "The largest sized string is: " << v[elem] << '\n';
   std::cout << "Largest string size is: " << v[elem].size() << '\n';
}
max element at: 1
The largest sized string is: bbbbb
Largest string size is: 5

There is a loop to find the largest sized string in the (possible) implementation of std::max_element, it simply isn't a loop the programmer has to write.
Unless you really need to know the element position, just de-reference result direct:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#include <algorithm>
#include <iostream>
#include <vector>
#include <string>

bool str_compare(const std::string& a, const std::string& b) {
    return a.size() < b.size();
}

int main() {
    const std::vector<std::string> v {"a", "bbbbb", "cc", "ddd", "eeee"};
    const auto result {std::max_element(v.begin(), v.end(), str_compare)};

    std::cout << "The largest sized string is: " << *result << '\n';
    std::cout << "Largest string size is: " << result->size() << '\n';
}


NB Pass std::string by const ref if a copy is not needed (or pass by std::string_view).
hiding a loop behind an interface is still a loop. Basic computing theory tells you that to know the max of a group, you have to look at every item in the group at some point. A loop is the generic and simple solution. However, you can also avoid the loop by keeping track 'as you go' :every time the vector is updated, check what was changed against the current largest value (keep the index and if you want, its size (index is sufficient)).

a wrapper for that..
struct wrapper
{
vector<string> vs;
uint64_t index;
unit64_t largest_size; //optional, vs[index].size() is identical.
};
//^^ add overloads for the vector functions you need that keep track...

then you don't ever need to look for it again. Its right there!
you trade a bit of complexity (all the overloads above) for speed (knowing the answer without unnecessary looping).
Sorry I should have specefied. By not using loops I meant "for", "while" and "do while" loops. We are forced to not use those in this assignment because they want use to use and learn STL algorithms instead.
ah. you can loop anything with the std::transform()
without a lot of effort. Its basically a lambda enabled syntax making a for loop of the form
for(init = begin; init < end; dosomething());

which is one of many ways to do the same thing -- and probably not the best for your task really. Carry on!

I dislike this stuff, immensely. Hiding stuff this way may make more modern looking code but I like to see a loop where it loops, so I can identify it easily and get rid of it if I need more speed. Most of the time (as seen in code, that is) these constructs serve no purpose beyond showing off. The ones that do a little more are extremely handy though (eg find first of and so on).
Last edited on
std::transform, std::for_each. Loops hidden within C++ standard library constructs.

std::transform has the advantage of allowing for alteration of a range of a container's elements and possibly storing the results in a different container. Or modifying in-place a single container's elements.

std::for_each uses a single container.

And a lambda doesn't have to be defined at its point of use, it can be done elsewhere. Doing so it can be used in multiple in-scope locations.
use and learn STL algorithms instead

I'm gonna beat a dead horse and "stir up controversy" by pointing out the STL is different from the C++ standard library.
http://kera.name/articles/2010/08/it-is-not-called-the-stl-mmkay/
Parts of the C++ Standard Library were based on parts of the STL, and it is these parts that many people (including several authors and the notoriously error-ridden cplusplus.com) still refer to as "the STL". However, this is inaccurate; indeed, the C++ standard never mentions "STL", and there are content differences between the two.

That is purely pedantic "fancy-froo-froo" flummery, technically correct, though most people will fully understand what is meant when talking about "using the STL."

I laugh the author of this screed singles out cplusplus for their rantings.

Let The Flame Wars BEGIN! :Þ

Another "take" on the STL vs. stdlib "controversy," written around the time C++11 was being worked on:
https://stackoverflow.com/questions/5205491/whats-the-difference-between-stl-and-c-standard-library

Now that C++20 is official, with C++23 being worked on, the C++ Standard Library has morphed, mutated and expanded enormously. The parts of the STL used to create the stdlib are now a small-ish part of the overall standard library. More modifications and additions will continue as the years roll on.
Last edited on
With C++20, the longest string in a vector of strings can be found using
1
2
auto iterator_pointing_to_longest_string 
  = std::ranges::max_element(my_vector, std::ranges::less{}, &std::string::size);
@mbozzi, it seems like the standard generally don't want us to use pointers to standard library functions.
https://eel.is/c++draft/namespace.std#6
Last edited on
@Peter87 Thanks! You taught me a new pitfall.

In this case std::ranges::size should work. This is an (customization point) object, not a function.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
#include <algorithm>
#include <functional>
#include <ranges>
#include <iostream>

int main()
{
  std::vector<std::string> my_vector{ "teal", "aqua", "azure", "cerulean", "cyan" };
  
  auto iterator_pointing_to_longest_string =
    std::ranges::max_element(my_vector, std::ranges::less{}, std::ranges::size);
    
  std::cout << *iterator_pointing_to_longest_string << '\n';
}
Last edited on
Topic archived. No new replies allowed.