Access matrix by an array indexing in C++

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
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);
	}
}
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.
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
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.
@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.

> 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
Holy crap!

/me mind=blown
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
@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.