In an array, how do I check if any two variables are equal in something like
total_milk[7] = { b_milk, e_milk, d_milk, g_milk, a_milk, m_milk, h_milk };
without using casework
Iterate over the elements in the array, adding each element to an unordered_set.
The return value from unordered_set::insert() will tell you whether the element already was in the set.
Use two for loops and compare each element with other elements:
bool anyTwo(total_milk a[], std::size_t n) {
for (std::size_t i = 0; i < n - 1; i++) {
for (std::size_t j = i + 1; j < n; j++) {
if (a[i] == a[j]) {
return true;
}
}
}
return false;
}
This assumes your overloaded the == operator in your class. The second for loop counter j starts from i + 1 instead of 0 or i as there is no need to compare the already compared values or compare the element with itself.
The naive approach, which is fine for small data sets, is to simply use a comparison loop where each element is compared with every other element following it - there's no point comparing with those at or before an element since either the comparison has already been done or you will be comparing an item with itself.
The following complete program illustrates this approach:
#include <iostream>
int milk[] = { 3, 1, 4, 1, 5, 9 };
int main() {
for (size_t one = 0; one < sizeof(milk) / sizeof(*milk) - 1; ++one) {
for (size_t two = first + 1; two < sizeof(milk) / sizeof(*milk); ++two) {
if (milk[one] == milk[two]) {
std::cout << "Duplicate item: " << milk[one] << '\n';
return 1;
}
}
}
std::cout << "No duplicates\n";
}
For larger data sets, you can turn to the more optimised collections provided by the C++ library, such as the sets. A set is able to hold one of each value and has the useful property that it will return the fact that you tried to insert a duplicate, by returning both an iterator to the inserted/original item and a boolean value indicating whether it was new or a duplicate.
Like the earlier program, this one shows how you can use this method:
#include <iostream>
#include <unordered_set>
int milk[] = { 3, 1, 4, 1, 5, 9 };
int main() {
std::unordered_set<int> checkSet;
for (auto val: milk) {
auto iterAndBool = checkSet.insert(val);
if (! iterAndBool.second) {
std::cout << "Duplicate item: " << val << '\n';
return 1;
}
}
std::cout << "No duplicates\n";
}
A substantial improvement could be made to that using templates. This would allow it to handle arrays of any data type (assuming it has equality operators, of course) without have to code up specialisations for each. The code for that would be along the following lines:
#include <iostream>
#include <unordered_set>
template<class T> T *CheckDupes(T *collection, size_t count) {
std::unordered_set<T> checkSet;
for (size_t idx = 0; idx < count; ++idx) {
auto iterAndBool = checkSet.insert(collection[idx]);
if (! iterAndBool.second) {
return &(collection[idx]);
}
}
return nullptr;
}
int milk[] = { 3, 1, 4, 1, 5, 9 };
int main() {
int *dupe;
if ((dupe = CheckDupes<int>(milk, sizeof(milk) / sizeof(*milk))) != nullptr) {
std::cout << "Duplicate item: " << *dupe << '\n';
return 1;
}
std::cout << "No duplicates\n";
}
The templated function above will either return nullptr (if there are no duplicates) or the address of one of the duplicates. It's a simple matter to check that return value and act appropriately.
I suspect further improvement could be made to handle other collection types (not just naked arrays) but I'll leave that as an exercise for when you've mastered simpler templates :-)
Related
Below I have attached code for a project that is intended to find the lowest value in a user-inputed vector, return -1 if the vector is empty, and 0 if the vector only has one index. I have run into an issue with the condition in which a vector is empty as the unit test continues to fail the returns_negative_one_for_empty_vector test.
main.cc
#include <iostream>
#include <vector>
#include "minimum.h"
int main() {
int size;
std::cout << "How many elements? ";
std::cin >> size;
std::vector<double> numbers(size);
for (int i = 0; i < size; i++) {
double value;
std::cout << "Element " << i << ": ";
std::cin >> value;
numbers.at(i) = value;
}
double index;
index = IndexOfMinimumElement(numbers);
std::cout << "The minimum value in your vector is at index" << index << std::endl;
}
minimum.cc
#include "minimum.h"
#include <vector>
int IndexOfMinimumElement(std::vector<double> input) {
int i, min_index;
double min_ = input.at(0);
for (int i = 0; i < input.size(); i++) {
if (input.at(i) < min_) {
min_index = i;
return min_index;
}
else if (input.size() == 0) {
return -1;
}
else if(input.size() == 1) {
return 0;
}
}
};
minimum.h
#include <vector>
int IndexOfMinimumElement(std::vector<double> input);
find the lowest value in a user-inputed vector, return -1 if the
vector is empty, and 0 if the vector only has one index.
Instead of writing raw for loops, this can be accomplished much more easily by using the STL algorithm functions.
There are other issues, one being that the vector should be passed by const reference, not by value. Passing the vector by-value incurs an unnecessary copy.
#include <algorithm>
#include <vector>
#include <iostream>
int IndexOfMinimumElement(const std::vector<double>& input)
{
if (input.empty())
return -1;
auto ptrMinElement = std::min_element(input.begin(), input.end());
return std::distance(input.begin(), ptrMinElement);
}
int main()
{
std::cout << IndexOfMinimumElement({ 1.2, 3.4, 0.8, 7.8 }) << std::endl;
std::cout << IndexOfMinimumElement({}) << std::endl; // empty
std::cout << IndexOfMinimumElement({3}) << std::endl; // only 1 element
return 0;
}
Output:
2
-1
0
The relevant functions are std::min_element and std::distance. The std::min_element returns an iterator (similar to a pointer) to the minimum element in the range.
The code is written with a clear understanding of what each function does -- it is practically self-documenting. To get the minimum element, you call std::min_element. To get the distance from the first to the found minimum element, you call std::distance with an iterator to the starting position and an iterator to the ending position.
The bottom line is this: the STL algorithm functions rarely, if ever, fail when given the proper input parameters. Writing raw for loops will always have a much greater chance of failure, as you have witnessed. Thus the goal is to minimize having to write such for loops.
In IndexOfMinimumElement you return on the very first iteration, as all branches of your if/else lead to a return.
If your vector contained {14, 2, 10, 1} the index it would return would be 1, because 2 is less than 14.
Instead, you want to have a couple of conditional checks at the top of your function that return based on the length of the vector.
If the function call gets past those, it should iterate over the values in the vector, checking if they are less than the running minimum value, and update the minimum index accordingly.
int IndexOfMinimumElement(std::vector<double> input) {
if (input.size() == 0) return -1;
if (input.size() == 1) return 0;
int i = 0;
double min = input[0];
int min_idx = 0;
for (auto &v : input) {
if (v < min) {
min = v;
min_idx = i;
}
++i;
}
return min_idx;
}
A minimal test:
int main() {
std::vector<double> foo { 1.2, 3.4, 0.8, 7.8 };
std::cout << IndexOfMinimumElement(foo) << std::endl;
return 0;
}
Prints, as expected:
2
I have an array of integers with a bunch of numbers from 1-10
Then I have an array of names(strings) which belong with the numbers a.e.
Numbers[0] = 5, Numbers[1] = 2
Names[0] = "Jeremy", Names [1] = "Samantha".
I can easily order the numbers with:
int n = sizeof(Numbers) / sizeof(Numbers[0]);
sort(Numbers, Numbers + n, greater<int>());
But then the names and numbers don't match at all.
How do I fix this?
A very common approach is to create an array of indices and sort that:
std::vector<int> indices(Numbers.size());
std::iota(indices.begin(), indices.end(), 0);
std::sort(indices.begin(), indices.end(),
[&](int A, int B) -> bool {
return Numbers[A] < Numbers[B];
});
The original arrays are not altered, but now indices can be used to access both arrays in the desired order.
If we want to reorder Numbers or Names in place, then we can
create a set of "back indices" that record where to find the element i in the sorted array:
std::vector<int> back_indices(indices.size());
for (size_t i = 0; i < indices.size(); i++)
back_indices[indices[i]] = i;
Now we can reorder, for example, Names in place in the desired order:
int index = 0;
std::string name = Names[index];
for (int i = 0; i < back_indices.size(); i++) {
index = back_indices[index];
std::swap(name,Names[index]);
}
I've tested this code which should give you the required behavior:
struct numberName {
int num;
string name;
};
bool compare(numberName a, numberName b){
return a.num < b.num; // if equal, no need to sort.
}
int main() {
numberName list[2];
list[0].num = 5, list[1].num = 2;
list[0].name = "Jeremy", list[1].name = "Samantha";
sort(list, list+2, compare);
}
Like HAL9000 said, you want to use a struct since this keeps variables that belong to each other together. Alternatively you could use a pair, but I don't know if a pair would be good practice for your situation or not.
This is a great example of the complexities introduced by using parallel arrays.
If you insist on keeping them as parallel arrays, here is a possible approach. Create a vector of integer indexes, initialised to { 0, 1, 2, 3, etc }. Each integer represents one position in your array. Sort your vector of indexes using a custom comparision function that uses the indexes to refer to array1 (Numbers). When finished you can use the sorted indexes to reorder array1 and array2 (Names).
One could also write their own sort algorithm that performs swaps on the extra array at the same time.
Or one could trick std::sort into sorting both arrays simultaneously by using a cleverly designed proxy. I will demonstrate that such a thing is possible, although the code below may be considered a simple hackish proof of concept.
Tricking std::sort with a cleverly-designed proxy
#include <iostream>
#include <algorithm>
constexpr size_t SZ = 2;
int Numbers[SZ] = {5, 2};
std::string Names[SZ] = {"Jeremy", "Samantha"};
int tempNumber;
std::string tempName;
class aproxy {
public:
const size_t index = 0;
const bool isTemp = false;
aproxy(size_t i) : index(i) {}
aproxy() = delete;
aproxy(const aproxy& b) : isTemp(true)
{
tempName = Names[b.index];
tempNumber = Numbers[b.index];
}
void operator=(const aproxy& b) {
if(b.isTemp) {
Names[index] = tempName;
Numbers[index] = tempNumber;
} else {
Names[index] = Names[b.index];
Numbers[index] = Numbers[b.index];
}
}
bool operator<(const aproxy& other) {
return Numbers[index] < Numbers[other.index];
}
};
int main() {
aproxy toSort[SZ] = {0, 1};
std::sort(toSort, toSort+SZ);
for(int i=0; i<SZ; ++i) {
std::cout << "Numbers[" << i << "]=" << Numbers[i] << std::endl;
std::cout << "Names[" << i << "]=" << Names[i] << std::endl;
}
return 0;
}
...and an even more cleverly-designed proxy could avoid entirely the need to allocate SZ "aproxy" elements.
Tricking std::sort with an "even more cleverly-designed" proxy
#include <iostream>
#include <algorithm>
class aproxy;
constexpr size_t SZ = 2;
int Numbers[SZ] = {5, 2};
std::string Names[SZ] = {"Jeremy", "Samantha"};
aproxy *tempProxyPtr = nullptr;
int tempNumber;
std::string tempName;
class aproxy {
public:
size_t index() const
{
return (this - reinterpret_cast<aproxy*>(Numbers));
}
bool isTemp() const
{
return (this == tempProxyPtr);
}
~aproxy()
{
if(isTemp()) tempProxyPtr = nullptr;
}
aproxy() {}
aproxy(const aproxy& b)
{
tempProxyPtr = this;
tempName = Names[b.index()];
tempNumber = Numbers[b.index()];
}
void operator=(const aproxy& b) {
if(b.isTemp()) {
Names[index()] = tempName;
Numbers[index()] = tempNumber;
} else {
Names[index()] = Names[b.index()];
Numbers[index()] = Numbers[b.index()];
}
}
bool operator<(const aproxy& other) {
return Numbers[index()] < Numbers[other.index()];
}
};
int main() {
aproxy* toSort = reinterpret_cast<aproxy*>(Numbers);
std::sort(toSort, toSort+SZ);
for(int i=0; i<SZ; ++i) {
std::cout << "Numbers[" << i << "]=" << Numbers[i] << std::endl;
std::cout << "Names[" << i << "]=" << Names[i] << std::endl;
}
return 0;
}
Disclaimer: although my final example above may technically be in violation of the strict-aliasing rule (due to accessing the same space in memory as two different types), the underlying memory is only used for addressing space-- not modified-- and it does seems to work fine when I tested it. Also it relies entirely on std::sort being written in a certain way: using a single temp variable initialized via copy construction, single-threaded, etc. Putting together all these assumptions it may be a convenient trick but not very portable so use at your own risk.
I have two std::vectors of same type, and I need to iterate through both of them using the same routine. Something like this:
std::vector<int> values1, values2;
int counter = 0;
for (int val : values1) counter += val;
for (int val : values2) counter += val;
Is there any simple way to write the last two lines in a single loop, to avoid code repetition? Something that would look like this:
std::vector<int> values1, values2;
int counter = 0;
for (int val : values1, values2) counter += val;
If you don't need to access either vector after iterating over them, you could move them into a std::initializer_list and then iterate over that:
std::vector<int> values1{1, 2, 3};
std::vector<int> values2{4, 5, 6};
for (const auto& v : {std::move(values1), std::move(values2)}) {
for (auto value : v) {
std::cout << value << ' ';
}
}
// prints "1 2 3 4 5 6 "
As ShadowRanger pointed out below, moving from the original vectors isn't necessary if we instead iterate over an initializer list of std::reference_wrappers. This can be done by swapping std::move with std::cref (or std::ref if you need to mutate them):
for (const auto& v : {std::cref(values1), std::cref(values2)}) {
for (auto value : v.get()) {
std::cout << value << ' ';
}
}
// prints "1 2 3 4 5 6 ", as before
No, there isn't, sorry. At least not directly in the language.
Boost can do it:
for (int val : boost::range::join(values1, values2))
counter += val;
Because Boost can do it, you could make something to do it as well, by making an iterator type of your own that casts a "view" over both collections.
But, particularly in the simple case you've shown, it's often not worth it. If your loop body is more complex, I recommend hiving it off into a function that takes int. This can just be a lambda declared immediately above the loop. That's what I do.
With range-v3 you could write:
namespace rs = ranges;
namespace rv = ranges::views;
int counter = rs::accumulate(rv::concat(values1, values2), 0);
I suspect there will be library support for this by C++23 (or C++2b). All that is needed is a range adaptor views::concat, and the range-ification of the <numeric> header.
How about:
std::vector<int> values_vecs[2];
// ...
int counter = 0;
for (const auto& values : values_vecs)
for (int val : values) counter += val;
It's not exactly the same as your original code, however it can support easily more than 2 vectors.
In case the vectors are there already as two separate vectors, you can still go with:
std::vector<int> values1, values2;
//...
int counter = 0;
for (auto values_ptr : {&values1, &values2})
for (int val : *values_ptr) counter += val;
I used something like this to iterate through 3 different vectors of different size where one vector was dependent of the two other vectors (first_vector is dependent on the other vectors).
#include <iostream>
#include <vector>
int main() {
std::vector<int> first_vector{50, 20, 30, 5000};
std::vector<int> second_vector{10};
std::vector<int> third_vector{500, 10};
for (int i = 0, j = 0, k = 0; i < first_vector.size(); ++i, ++j, ++k) {
if (j == second_vector.size()) {
j = 0;
}
if (k == third_vector.size()) {
k = 0;
}
std::cout << first_vector[i] << '|' << second_vector[j] << '|'
<< third_vector[k] << '\n';
std::cin.get();
}
return 0;
}
I know how to check if number exist in the array, but not in a 2D array.
Please help me in 2D.
#include<iostream>
using namespace std;
int main()
{
int a[3] = { 4,5,6 };
int b, c;
int x = 1, fact = 1;
cout << "enter no ";
cin >> b;
for (int i = 0; i < 3; i++)
{
if (b == a[i]) {
c = a[i];
break;
}
}
cout << "no entered is present" << endl;
}
I know how to check if number exist in the array, but not in 2D array!
It is like you did for the one-dimensional array, instead of one, you need to now iterate through the rows and column. In another word, you need one more iteration.
#include<iostream>
int main()
{
int a[2][3]{ { 1,2,3 }, { 4,5,6 } };
int userInput = 5;
bool found = false;
for (int row = 0; !found && row < 2; ++row) // if not found and row size < 2
{
for (int col = 0; col < 3; ++col) // if column size < 3
{
if (userInput == a[row][col]) // access the element like this
{
// other codes
std::cout << "No entered is present\n";
found = true;
break;
}
}
}
}
However, using the row size and column size like this, I will not recommend so. You should be using better std::array(if you know the size at compile time), or std::vector(if the sizes are known at run time).
For example, using std::array you could have the following code(example code). Using the range based for-loop, and a simple function makes the code more readable and less error-prone. Also, you need to know the sizes known at compile time. (See live demo)
#include <iostream>
#include <array> // std::array
bool isIn2DArray(const std::array<std::array<int, 3>, 2>& arr, int val) /* noexcept */
{
// range based for-loop instead of index based looping
for (const std::array<int, 3> & row : arr)
for (const int element : row)
if (element == val)
return true; // if found in the array, just return the boolean!
return false; // if not found!
}
int main()
{
std::array<std::array<int, 3>, 2> a{ { { 1,2,3 }, { 4,5,6 } } };
int userInput = 5;
if (isIn2DArray(a, userInput)) // you call the function like this!
{
std::cout << "Found in the array!\n";
}
else
{
std::cout << "Didn't find!\n";
}
}
In case of wondering, how to provide isIn2DArray for any arbitrary array, do it by providing the sizes as non-template parameters as below. (See live demo)
#include <array> // std::array
template<std::size_t Row, std::size_t Col>
bool isIn2DArray(const std::array<std::array<int, Col>, Row>& arr, int val)/* noexcept */
{
// range based for-loop instead of index based looping
for (const std::array<int, 3> & row : arr)
for (const int element : row)
if (element == val)
return true; // if found in the array, just return the boolean!
return false; // if not found!
}
If the array is an actual 2D array, if you know how to check if a number exists in a 1D array, you can use the exact same code to determine if a value exists in a regular 2D array.
The trick is to write the code using pointers to the start and ending elements of the array. The reason why is that a 2D array stores its data in contiguous memory, no different than a 1D array.
Here is an example of the same search function working for both 1-dimensional and 2-dimensional arrays:
#include<iostream>
bool exists(int *start, int *end, int value)
{
while (start != end)
{
if ( value == *start )
return true;
++start;
}
return false;
}
int main()
{
int a[3] = {4,5,6};
bool found = exists(a, a + 3, 5);
if ( found )
std::cout << "The number 5 was found\n";
else
std::cout << "The number 5 was not found\n";
// now a 2d array
int a2[3][4] = {{1,2,3,4},{7,8,9,10},{2,43,2,0}};
found = exists(&a2[0], &a2[2][4], 43);
if ( found )
std::cout << "The number 43 was found\n";
else
std::cout << "The number 43 was not found\n";
found = exists(&a2[0][0], &a2[2][4], 11);
if ( found )
std::cout << "The number 11 was found\n";
else
std::cout << "The number 11 was not found\n";
// Let's try a 3D array for fun
int a3[2][3][4] = {{{1,2,3,4},{7,8,9,10},{2,43,2,0}},
{{6,9,1,56},{4,8,2,10},{2,43,2,87}}};
found = exists(&a3[0][0][0], &a3[1][2][4], 56);
if ( found )
std::cout << "The number 56 was found\n";
else
std::cout << "The number 56 was not found\n";
}
Output:
The number 5 was found
The number 43 was found
The number 11 was not found
The number 56 was found
Surprisingly, the same function worked for 1-dimensional, 2-dimensional arrays, and even 3 dimensional arrays, all due to the data being stored in contiguous memory.
The address of the starting element, and the address of one past the ending element in the array are provided to the function, thus the function knows where to start and where to end the search.
bool check2dArray(vector<vector<int>> mat, int n){
int rows = mat.size();
if (rows==0) return false;
int cols = mat[0].size();
for (int i=0; i<rows; i++){
for (int j=0; j<cols; j++){
if (n == mat[i][j]) return true;
}
}
return false;
}
template <class Matrix, class CheckValue>
bool CheckExists(const Matrix& M, const CheckValue& Value) {
for (const auto& m : M)
for (const auto& v : m)
if (v == Value)
return true;
return false;
}
int main(int, char**)
{
int cArray[10][100]; auto exists = CheckExists(cArray, 10);
std::vector<std::vector<int>> vec; exists = CheckExists(vec, 0);
std::array<std::array<int, 10>, 100> arr; exists = CheckExists(arr, 0);
return 0;
}
This should be really simple, but I'm used to higher level languages and am missing something. I'm just trying to make sure the input is five numbers long, and then find the highest number. Unfortunately, something goes wrong in that second part.
#include <iostream>
#include <string>
bool isFiveDigits(int num) {
if (std::to_string(num).length() == 5) {
return true;
} else {
return false;
}
}
int highestInArr(int *nums) {
int highest = nums[0];
for (int i = 1; i < sizeof(nums); i++) {
int temp = nums[i];
if (temp > highest) {
highest = temp;
}
}
return highest;
}
int main() {
using namespace std;
int num;
int nums [5];
cout << "Enter a five digit number!\n";
cin >> num;
if (!isFiveDigits(num)) {
cout << "Not five digits, can you even count?";
return 1;
}
string numstr = to_string(num);
for (int i = 0; i < numstr.length(); i++) {
cout << numstr[i] << " ";
nums[i] = (int)numstr[i];
}
cout << "\n" << highestInArr(nums);
}
When this runs, I get:
Enter a five digit number!
12345
1 2 3 4 5
1424080487
Of course, 1,424,080,487 is not in [1, 2, 3, 4, 5].
You cannot pass a pointer into a function and get the size of it without template deduction. At runtime, all the function receives is a pointer. When you call sizeof(nums), you are not getting the size of the original array. You are simply getting the size of the pointer, which is the same as saying sizeof(int_ptr). Instead, you should be using a std::vector when using collections whose sizes are dynamic.
Now, you CAN receive the size by doing something like this:
#include <iostream>
template<typename num_t, size_t N>
num_t max_num(num_t(&arr)[N]) {
num_t m = (num_t)0;
for (size_t i = 0; i < N; ++i)
if (arr[i] > m)
m = arr[i];
return m;
}
int main(){
int foo[] = { 1, 5, 2, 4, 3 };
int m = max_num(foo);
std::cout << m << std::endl;
std::cin.get();
return 0;
}
However, this is not necessarily preferred and assumes that the array was created on the caller's stack. It does not work for dynamically allocated arrays that were created with new[]. If you do this multiple times with different sizes, you will have multiple implementations of the same function (that's what templates do). The same goes for using an std::array<int, N>. If you use N as a size_t template parameter, it will do the same thing.
There are two preferred options:
Send the size of the array into the function so that the caller is responsible for the size.
Use a different container such as std::vector so the callee is responsible for the size.
Example:
#include <vector>
#include <iostream>
#include <algorithm>
int main(){
std::vector<int> vec{ 1, 5, 2, 4, 3 };
int m = *std::max_element(std::cbegin(vec), std::cend(vec));
std::cout << m << std::endl;
std::cin.get();
return 0;
}
As for the is_5_digits, you should use the base-10 logarithm function.
#include <cmath>
// ...
int i = 12345;
size_t length = (i > 0 ? (int)log10(i) : 0) + 1;
std::cout << length << std::endl; // prints 5;
First of all, you can't simply convert a char to int just like (int)numstr[i] assuming that it will return the digit which it contains.
See, if you have a char '0', it means it's ASCII equivalent is stored, which is 48 in case of 0, 49 in case of '1' and so on.
So in order to get that digit (0,1,2,...,9), you've to substract 48 from the ASCII value.
So change this line:
nums[i] = (int)numstr[i];
to:
nums[i] = (int)numstr[i] - 48; // or nums[i] = (int)numstr[i] - '0';
And another thing, in your highestInArr function, you're getting a pointer as parameter, and in the function, you're using sizeof to determine the size of the array. You can't simply do that, the sizeof will return the size of int*, which is not the size of the array, so you've to pass size as the second argument to the function, and use it in the loop.
Like this:
int highestInArr(int *nums, int size) {
// ...
for (int i = 1; i < size; i++) {
// ...
}
// ...
}