Access matrix by an array indexing in C++

Mar 2, 2016 at 5:51pm
Dear Friends,

I am wondering whether there is a C++ function written by someone can do the following matrix operation.

Thanks,
L
-------------
MATLAB supports a type of array indexing that uses one array as the index into another array. You can base this type of indexing on either the values or the positions of elements in the indexing array.

Here is an example of value-based indexing where array B indexes into elements 1, 3, 6, 7, and 10 of array A. In this case, the numeric values of array B designate the intended elements of A:

A = 5:5:50
A =
5 10 15 20 25 30 35 40 45 50
B = [1 3 6 7 10];

A(B)
ans =
5 15 30 35 50
Mar 2, 2016 at 7:33pm
You could try something like this:

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
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
#include <iostream>
#include <utility>
#include <vector>

typedef std::vector<unsigned> IndexArray;

template<typename TYPE>
class DataVector
{
public:
	void addMember(TYPE t) { array.push_back(t); }
	std::pair<bool, DataVector<TYPE> > operator()(const IndexArray& indices);
	void display(std::ostream& outfile);

	void reserve(unsigned size) { array.reserve(size); }
	void clear() { array.clear(); }
private:
	std::vector<TYPE> array;
};


template<typename TYPE>
std::pair<bool, DataVector<TYPE> >
DataVector<TYPE>::operator()(const IndexArray& indices)
{
	bool ok = true;

	DataVector<TYPE> ret;
	ret.reserve(indices.size());

	for (int i = 0; i < indices.size(); ++i)
	{
		if (indices[i] > array.size())
		{
			ok = false;
			ret.clear();
			break;
		}
		else
		{
			ret.addMember(array[indices[i] - 1]);
		}
	}

	return std::make_pair(ok, ret);
}


template<typename TYPE>
void DataVector<TYPE>::display(std::ostream& outfile)
{
	for (int i = 0; i < array.size(); ++i)
	{
		outfile << array[i] << " ";
	}
	outfile << std::endl;
}

int main()
{
	DataVector<int> A;
	for (int i = 5; i <= 50; i+= 5)
	{
		A.addMember(i);
	}

	IndexArray B;
	B.push_back(1);
	B.push_back(3);
	B.push_back(6);
	B.push_back(7);
	B.push_back(10);

	std::pair<bool, DataVector<int> > retVal = A(B);
	if (retVal.first == true)
	{
		retVal.second.display(std::cout);
	}
}
Mar 2, 2016 at 7:56pm
Yes, easily, only, C++ syntax is not as compact as MATLAB's.

Here's one way to do it:

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
#include <algorithm>
#include <iostream>
#include <iterator>
#include <vector>

template <typename Container, typename T>
Container& iota( Container& s, T first, T increment, T last )
{
  while (first <= last)
  {
    s.push_back( first );
    first = first + increment;
  }
  return s;
}

int main()
{
  std::vector <int> A;  iota( A, 5, 5, 50 );
  std::vector <int> B{ 0, 2, 5, 6, 9 };
  
  std::vector <int> ans;
  for (int n : B) ans.push_back( A[n] );  // == A[B[index]]
  
  for (int n : ans)
    std::cout << n << " ";
  std::cout << "\n";
}

Hope this helps.
Mar 3, 2016 at 8:27pm
Thanks, Doug4. I compiled your code, but errors :

"ld: symbol(s) not found for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)"

Does it work at your end?

L
Mar 3, 2016 at 9:56pm
I don't wish to be rude to Doug4, but why are you wasting time with an overly-complex solution that redesigns a common class?

With all that work, it is not even as simple to initialize as the standard C++ methods, let alone MATLAB's.
Mar 4, 2016 at 3:21pm
@Duoas,

No rudeness taken. I was intrigued with this question and wasted my lunch hour slapping something together. My solution is more complex that the way you wrote it.

My main goal was trying to mimic the matlab notation A(B);. That's why I made it a class. Then I started adding error checking and utilities, and things got more cluttered. I could have stripped it down to a sleeker version, but I was in my error-catching mode.

@OP,

Yes, my code compiles and works. I have no idea what symbol your compiler does not see. Your error message is almost meaningless.

Mar 4, 2016 at 4:17pm
> MATLAB supports a type of array indexing that uses one array as the index into another array.

C++ has std::indirect_array.
std::valarray<> and friends would come closest to MATLAB-like array operations in C++.
http://en.cppreference.com/w/cpp/header/valarray

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
#include <iostream>
#include <valarray>
#include <iomanip>

int main()
{
    std::valarray<int> a = { 5, 10, 15, 20, 25, 30, 35, 40, 45, 50 } ;
    std::valarray<std::size_t> b = { 1, 3, 6, 7, 10 } ;
    b -= 1 ; // index of the first element in C++ sequences is zero, not one

    const std::valarray<int> c = a[b] ; // construct from indirect_array

    for( int v : c ) std::cout << v << ' ' ;
    std::cout << '\n' ;

    for( int v : a ) std::cout << std::setw(6) << v ;
    std::cout << '\n' ;

    const std::valarray<int> d = a * 99 ;
    a[b] += d[b] ; // modify a via indirect array

    for( int v : a ) std::cout << std::setw(6) << v ;
    std::cout << '\n' ;

    a[ a%100 == 0 ] = -9 ; // assign -9 to elements that are divisible by 100 (via mask array)

    for( int v : a ) std::cout << std::setw(6) << v ;
    std::cout << '\n' ;
}

http://coliru.stacked-crooked.com/a/8ff27dc2f10e76f7
Mar 5, 2016 at 12:17am
Holy crap!

/me mind=blown
Mar 5, 2016 at 12:39am
Dear JLBorges,

This is great. Thank you very much.

L

-----------------------

Dear doug4 and Duoas,

Thanks for your time spending on my question. I still learned valuable things from your codes.

All the best,
L
Mar 5, 2016 at 4:15am
@doug4
Yeah, that was what got my interest in this question too... JLBorges continues to teach me about cool stuff too.
Topic archived. No new replies allowed.