Compare two lines of arrays and return the elements that are in the first, but not the second

So i have 2 lines of arrays. First line is M, second line is N. On the first line the user inputs 2 digits, first for the length of M, and second for the length of N. On the second line user inputs M, on the third - N. All i want is to display what elements of N are not contained in m, but in ascending order. Here's an example:

7 5

3.12 7.96 3.51 4.77 10.12 1.11 9.80

10.12 3.51 3.12 9.80 4.77

Output:

1.11 7.96

And here is my attempt at the program:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
      #include<stdio.h>
    #include <iostream>
    #include <stdio.h>
    #include <string.h>
    #include <math.h>
    #include <stdlib.h>
    #include <vector>
    #include <algorithm>
    using namespace std;


    int ifexists(double z[], int u, int v)
    {
    int i;
    if (u == 0) return 0;
    for (i = 0; i <= u; i++)
        if (z[i] == v) return (1);
    return (0);
    }

    int main()
    {
    double bills[100], paid[100], result[100];
    int m, n;
    int i, j, k;
    cin >> m >> n;
    if (n > m) {
        cout << "Wrong input.";
        exit(3);
    }
    for (int i = 0; i < m; i++) {
        cin >> bills[i];
    }
    for (int i = 0; i < n; i++) {
        cin >> paid[i];
    }  
    for (i = 0; i < n; i++)                                                                                    
    k = 0;
    for (i = 0; i < m; i++)
    {
        for (j = 0; j < n; j++)
        {
            if (bills[i] == paid[j])
            {
                break;
            }
        }
        if (j == n)
        {
            if (!ifexists(result, k, bills[i]))
            {
                result[k] = bills[i];
                k++;
            }
        }
    }
    for (i = 0; i < k; i++)
        cout << result[i] << " ";
    return 0;
    }


The output i'm getting is almost correct - 7.96 1.11. Basically in reverse order. How can i flip this around? Also, chances are my report is too slow. Is there a way to increase the speed?
Well the first thing to do is sort both arrays.

This fixes your first problem, because your output will be sorted for free at that point anyway.
The standard library has sort already implemented, and it's very efficient.

It also vastly improves your search speed, because you only need to go through both arrays once.

Consider
b = 1 2 4 5
and
p = 2 5

b[0] < p[0], so b[0] is unpaid, and you move on to b[1]
b[1] == p[0], so it's paid and you move to b[2] and p[1]
etc

Look at std::set_difference http://www.cplusplus.com/reference/algorithm/set_difference/
It requires sorted ranges.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
#include <iostream>
#include <algorithm>
#include <sstream>
#include <string>

using namespace std;

int ifexists(double z[], int u, int v)
{
    int i;
    if (u == 0) return 0;
    for (i = 0; i <= u; i++)
        if (z[i] == v) return (1);
    return (0);
}

int main()
{
    std::string file("7 5 3.12 7.96 3.51 4.77 10.12 1.11 9.80 10.12 3.51 3.12 9.80 4.77");
    std::istringstream in( file );

    double bills[100], paid[100], result[100];
    int m, n;
    in >> m >> n;
    if (n > m) {
        cout << "Wrong input.";
        return 3;
    }
    for (int i = 0; i < m; i++) {
        in >> bills[i];
    }
    for (int i = 0; i < n; i++) {
        in >> paid[i];
    }  

    std::sort( bills, bills+m );
    std::sort( paid, paid+n );

    auto it = std::set_difference( bills, bills+m, paid, paid+n, result );
    int k = it - result;
    for ( int i = 0; i < k; i++)
        cout << result[i] << " ";
    return 0;
}

Since your "set_difference" operates correctly(?) on unsorted data, it is sufficient to just sort the "result" before you show it:

1
2
3
4
5
    std::sort( result, result+k );
    for ( int i = 0; i < k; i++)
        cout << result[i] << " ";
    return 0;
}

All i want is to display what elements of N are not contained in m


Don't you mean elements of M not contained in N - as M is the larger set? 1.11 and 7.96 come from M, not N.

Probably the easiest way is to create a set from M, then remove those elements from N that exist and what's left is what is not contained in N. Also, this way you don't need to know the size of the input data. Consider:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#include <sstream>
#include <set>
#include <iostream>
#include <string>

int main()
{
	const std::string M {"3.12 7.96 3.51 4.77 10.12 1.11 9.80"};
	const std::string N {"10.12 3.51 3.12 9.80 4.77"};

	std::set<double> sm;
	std::istringstream mss(M);
	std::istringstream nss(N);

	for (double m {}; mss >> m; sm.insert(m));
	for (double n {}; nss >> n; sm.erase(n));
	for (const auto& v : sm)
		std::cout << v << ' ';

	std::cout << '\n';
}



1.11 7.96


or to obtain the data from a file when you need the sizes, consider:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
#include <fstream>
#include <set>
#include <iostream>
#include <string>

int main()
{
	std::ifstream ifs("nm.txt");

	if (!ifs.is_open())
		return (std::cout << "Cannot open input file\n"), 1;

	size_t m {}, n {};

	if ((ifs >> m >> n) && (n < m)) {
		std::set<double> sm;
		double v {};

		for (size_t m1 = 0; m1 < m && ifs >> v; ++m1)
			sm.insert(v);

		for (size_t n1 = 0; n1 < n && ifs >> v; ++n1)
			sm.erase(v);

		for (const auto& v : sm)
			std::cout << v << ' ';

		std::cout << '\n';
	} else
		std::cout << "Problem reading sizes\n";
}

Last edited on
Topic archived. No new replies allowed.