C++ std::map set and get using operator[] - operator-overloading

I'm trying to build a 2D sparse matrix class using std::map, which should be called in (for example) the following way:
SparseMatrix<double> M(2,2); // Create a new sparse matrix with 2 rows and 2 columns
M[{1,1}] = 3.1; // Sets element {1,1} to 3.1
The following class can perform these tasks:
template < typename T >
class SparseMatrix
{
std::map< array<int, 2>, T> data;
const array<int, 2> size;
public:
SparseMatrix(const int rows, const int cols)
: size({ rows, cols }) {}
// []-operator to set and get values from matrix
T& operator[](const array< int,2 > indices)
{
// Check if given indices are within the size of the matrix
if(indices[0] >= size[0] || indices[1] >= size[1])
throw invalid_argument("Indices out of bounds");
return data[indices];
}
};
Using this class it is possible to create a new object and set the element, however, the []-operator is also used to get elements, for example:
std::cout << M[{1,1}] << std::endl;
The problem with this is that if this is used to get an element that is not set already, it creates a new part in the map with the given indices and a value of 0, which is undesired for a sparse matrix class, as the map should only contain the non-zero elements.
Is it possible to solve this problem with the []-operator by making a distinction between 'setting' and 'getting'? In case of 'getting' should the operator only return a 0 without adding it to the map.

You can differentiate between reading and writing by using a proxy instead of a T&. Only showing the relevant code:
template <typename T>
class SparseMatrixProxy {
public:
//for reading an element:
operator T() const {
// Check if given indices are within the size of the matrix
if (indices[0] >= matrix.size[0] || indices[1] >= matrix.size[1])
throw std::invalid_argument("Indices out of bounds");
auto map_it = matrix.data.find(indices);
if (map_it == matrix.data.end()) {
return T{};
}
return map_it->second;
}
//for writing an element:
auto operator=(const T &t) {
//optional: when setting a value to 0 erase it from the map
if (t == T{}) {
matrix.data.erase(indices);
} else {
matrix.data[indices] = t;
}
return *this;
}
};
to be used in SparseMatrix like this:
// []-operator to set and get values from matrix
SparseMatrixProxy<T> operator[](const std::array<int, 2> indices) {
return {*this, indices};
}
With usage:
SparseMatrix<double> M(2, 2); // Create a new sparse matrix with 2 rows and 2 columns
M[{{1, 1}}] = 3.1; // Sets element {1,1} to 3.1
std::cout << M[{{1, 1}}] << '\n';
assert(M.mapsize() == 1); //1 element for index {1,1}
std::cout << M[{{0, 0}}] << '\n';
assert(M.mapsize() == 1); //still 1 element because reading doesn't insert an element
M[{{1, 1}}] = 0;
assert(M.mapsize() == 0); //0 elements because we set the only non-0 element to 0
Complete example.

There is std::map::find method. It returns an iterator and if it equals to map.end() then it means that the element is absent in the map.

Yup, it's a pain in the backside. Luckily the clever C++11 bods realised this and gave us a new method: at.
Use the at method (available from the C++11 standard onwards), which does not do any insertion, although you still need a catch handler for a possible std::out_of_range exception.
See http://en.cppreference.com/w/cpp/container/map/at

It's cheaper from performance point of view to implement sparse matrix by creating own mapping, e.g via storing indices.
template<typename T>
class SparseMatrix
{
...
int m, n;
vector<T> values;
vector<int> cols;
vector<int> rows;
}
template<typename T>
T SparseMatrix<T>::get(int row, int col) const
{
this->validateCoordinates(row, col);
int currCol = 0;
for (int pos = rows.at(row - 1) - 1; pos < rows.at(row) - 1; pos++)
{
currCol = cols.at(pos);
if (currCol == col)
return vals.at(pos);
else if (currCol > col)
break;
}
return T();
}
template<typename T>
SparseMatrix<T> & SparseMatrix<T>::set(T val, int row, int col)
{
// Validate coordinates here?
int pos = rows.at(row - 1) - 1;
int currCol = 0;
for (; pos < rows.at(row) - 1; pos++) {
currCol = cols.at(pos);
if (currCol >= col) {
break;
}
}
if (currCol != col) {
if (!(val == T())) {
this->insert(pos, row, col, val);
}
} else if (val == T()) {
this->remove(pos, row);
} else {
vals.at(pos) = val;
}
return *this;
}
template<typename T>
void SparseMatrix<T>::insert(int index, int row, int col, T val)
{
vals.insert(vals.begin() + index, val);
cols.insert(cols.begin() + index, col);
for (int i = row; i <= this->m; i++)
rows.at(i) = rows.at(i) + 1;
}
And so on...

Related

How to use selection sort in objects and classes

I'm creating two classes called stop watch and random numbers, which I have already done, but I needed to create a test program that would measure the execution time of sorting 100,000 numbers using selection sort. I know how to create a selection sort, I just don't know how to take the random numbers class and put it together with the selection sort, I get the error message "incompatible types random numbers cannot be converted to int" I hope someone can help me.
My random numbers class
import java.util.Random;
public class randomnumbers {
Random ran1 = new Random();
private int size;
public randomnumbers(){
size = 100000;
}
public int getSize(){
return size;
}
public void setSize(int newSize){
size = newSize;
}
public int [] createArray(int [] size){
for (int i = 0; i < size.length; i++){
size[i] = ran1.nextInt();
}
return size;
}
public static void printArray (int [] array){
for (int i = 0; i < array.length; i++){
if (i < 0){
System.out.println(array[i] + " ");
}
}
}
}
My test Program
public static void main (String [] args){
// Create a StopWatch object
StopWatch timer = new StopWatch();
//create random numbers
randomnumbers numbers = new randomnumbers();
//Create the size of the array
numbers.getSize();
// Invoke the start method in StopWatch class
timer.start();
//sort random numbers
selectionSort();
// Invoke the stop method in StopWatch class
timer.stop();
// Display the execution time
System.out.println("The execution time for sorting 100,000 " +
"numbers using selection sort: " + timer.getElapsedTime() +
" milliseconds");
}
// selectionSort performs a selection sort on an array
public static void selectionSort(int[] array) {
for (int i = 0; i < array.length - 1; i++) {
int min = array[i];
int minIndex = i;
for (int j = i + 1; j < array.length; j++) {
if (array[j] < min) {
min = array[j];
minIndex = j;
}
}
if (i != minIndex) {
array[minIndex] = array[i];
array[i] = min;
}
}
}
}
Where exactly are you getting "incompatible types random numbers cannot be converted to int" error?
There are multiple issues with the code:
Unconventional naming
size field is in randomnumbers class is used as actual array size in constructor but in createArray it's overshadowed with a parameter of the same name but different type and meaning.
You are not passing any array to selectionSort in Main. This is where I get compile error on your code.
printArray has if (i < 0) condition that is false for all ran1.nextInt() numbers so it will not print anything.
Feeding selectionSort with numbers.createArray(new int[numbers.getSize()]) compiles and ends up sorting the array.

Unpacking iterable in Python extension

I'm trying to translate a, b, c, d = iterable to Python's C/API.
I'm looking for a function similar to PyArg_ParseTuple, just for iterables.
In other words, something in the area of PyIter_Parse or PyObject_ParseIterable, if such functions would have existed.
Any tips how to implement it?
No, there is no helper function that can do this for you.
You'd have to use PyIter_Next() up to max times to retrieve values, raise an exception when you can't get at least min values, and then just build a tuple from that.
Something like (untested, largely pilfered from PySequence_Tuple()):
int
PyIter_LimitedTuple(PyObject *v, Py_ssize_t min, Py_ssize_t max)
{
PyObject *it; /* iter(v) */
PyObject *result = NULL;
Py_ssize_t j;
it = PyObject_GetIter(v);
if (it == NULL)
return NULL;
/* allocate space. */
result = PyTuple_New(max);
if (result == NULL)
goto Fail;
/* Fill the tuple. */
for (j = 0; ; ++j) {
PyObject *item = PyIter_Next(it);
if (item == NULL) {
if (PyErr_Occurred())
goto Fail;
break;
}
if (j > max) {
PyErr_Format(PyExc_ValueError,
"too many values to unpack");
goto Fail;
}
PyTuple_SET_ITEM(result, j, item);
}
if (j < min) {
PyErr_Format(PyExc_ValueError,
"need more than %d value to unpack",
j);
goto Fail;
}
/* Cut tuple back if fewer than max items were available. */
if (j < max &&
_PyTuple_Resize(&result, j) != 0)
goto Fail;
Py_DECREF(it);
return result;
Fail:
Py_XDECREF(result);
Py_DECREF(it);
return NULL;
}
then pass the resulting tuple to PyArg_UnpackTuple().

Attempts to call a method in the same class not working (java)

I'm creating a random number generator which then sorts the digits from largest to smallest. Initially it worked but then I changed a few things. As far as I'm aware I undid all the changes (ctrl + z) but now I have errors at the points where i try to call the methods. This is probably a very amateur problem but I haven't found an answer. The error i'm met with is "method in class cannot be applied to given types"
Here's my code:
public class RandomMath {
public static void main(String[] args) {
String bigger = bigger(); /*ERROR HERE*/
System.out.println(bigger);
}
//create method for generating random numbers
public static int generator(int n){
Random randomGen = new Random();
//set max int to 10000 as generator works between 0 and n-1
for(int i=0; i<1; i++){
n = randomGen.nextInt(10000);
// exclude 1111, 2222, 3333, 4444, 5555, 6666, 7777, 8888, 9999, 0000
if((n==1111 || n==2222 || n==3333 || n ==4444 || n==5555)
||(n==6666 || n==7777 || n==8888 || n==9999 || n==0000)){
i--;
}
}
return n;
}
//create method for denoting the bigger number
public static String bigger(int generated){
generated = generator(); /*ERROR HERE*/
System.out.println(generated);
int[] times = new int[10];
while (generated != 0) {
int val = generated % 10;
times[val]++;
generated /= 10;
}
String bigger = "";
for (int i = 9; i >= 0; i--) {
for (int j = 0; j < times[i]; j++) {
bigger += i;
}
}
return bigger;
}
}
You have not defined a method bigger(), only bigger(int generated). Therefore, you must call your bigger method with an integer parameter.

issue in my if statement to make comparison in my java program

any help please, so i already wrote the prog but my if statement in my for loop is not working. the prog need to generate 6 random nos,then apply bubble sort which i already did.then the user must enter 6 numbers and these numbers must be compared against the random numbers and must say whether numbers are found in the random numbers or not. here's the code. something is wrong with the if statement ` public static void main(String[] args) {
try {
int numbers[] = new int[6]; //random numbers will be stored in new array
//2 loop will be created to avoid duplication of numbers
System.out.println("Array before Bubble sort");
for (int i = 0; i < 6; i++) {
numbers[i] = (int) (Math.random() * 40);
if (i > 0) {
for (int b = 0; b < i; b++) { //
if (numbers[b] == numbers[i]) {
i--; //decrement to continue the for loop if the integer has been repeated
}
}
}
System.out.print(numbers[i] + ","); //random numbers will be printed before using sorting bubble sort
}
//sort an array using bubble sort
bubbleSort(numbers);
System.out.println(" \nArray after bubble sort");
for (int i = 0; i < 6; i++) {
System.out.print(numbers[i] + ",");
}
BufferedReader input = new BufferedReader(new InputStreamReader(System.in));
System.out.println("\ninput 6 number between 1 and 40");
int inputNumber = Integer.parseInt(input.readLine());
for (int b = 0; b < 6; b++) {
System.out.println("number:");
int outcome=Integer.parseInt(input.readLine());
if(outcome==numbers){
System.out.println("found in random numbers");
}else{
System.out.println("not found in random numbers");
}
}
} catch (Exception e) {
System.out.println("error");
}
}
public static void bubbleSort(int[] numbers) {
int n = numbers.length;
int temp = 0;
for (int i = 0; i < n; i++) {
for (int j = 1; j < (n - i); j++) {
if (numbers[j - 1] > numbers[j]) { //swap the element
temp = numbers[j - 1];
numbers[j - 1] = numbers[j];
numbers[j] = temp;
}
}
}
}
}`
System.out.println("\ninput 6 number between 1 and 40");
//Scanner is specifically designed for getting an input purpose and introduced in Java 5,so better use it
Scanner s = new Scanner(System.in);
//you need to have nested loop here
//But the best way to search is use binary search,as you have already sorted the array
while (s.hasNextInt()) {
//one at a time from the input is put to outcome
int outcome = s.nextInt();
boolean found = false;
for (int b = 0; b < 6; b++) {
found = false;
if (outcome == numbers[b]) {
found = true;
//remember to break the inner loop if a match is found
break;
} else {
found = false;
}
}
if (found == true) {
System.out.println("found in random numbers");
} else {
System.out.println("not found in random numbers");
}

Creating a Linked list with Structs - C++

I was writing a program which could read an input file and store the read data in nodes linked by a "link list". However, I was getting a few errors:
In constructor List::List(), no match for 'operator =' in *((List*)this)->List::list[0] = 0
In constructor Polynomial::Polynomial(): no match for 'operator =' in *((Polynomial*)this)->Polynomial::poly = (operator new(400u), (<statement>), ...)
I have a feeling where I do: I try to access a certain node through an array is where I go wrong, however, I can't figure it out much.
Here is the code:
#include <iostream>
#include <fstream>
using namespace std;
enum result{success, failure};
struct Node
{
double coefficient;
int power;
Node();
Node(double coef, int pwr);
};
struct List
{
Node *list[100];
//Default constructor
List();
};
Node::Node()
{
coefficient = 0;
power = 0;
}
List::List()
{
*list[0] = NULL;
}
Node::Node(double coef, int pwr)
{
coefficient = coef;
power = pwr;
}
class Polynomial
{
public:
Polynomial();
result multiply(Polynomial &p, Polynomial &q);
result add(Polynomial p, Polynomial &q);
void initialize(ifstream &file);
void simplify(Polynomial &var);
void print_poly();
~Polynomial();
private:
List *poly; //Store the pointer links in an array
Node first_node;
int val;
};
Polynomial::Polynomial()
{
*poly = new List();
}
Polynomial::void initialize(ifstream &file)
{
int y[20];
double x[20];
int i = 0, j = 0;
//Read from the file
file >> x[j];
file >> y[j];
first_node(x[j], y[j++]); //Create the first node with coef, and pwr
*poly->list[i] = &first_node; //Link to the fist node
//Creat a linked list
while(y[j] != 0)
{
file >> x[j];
file >> y[j];
*poly->list[++i] = new Node(x[j], y[j++]);
}
val = i+1; //Keeps track of the number of nodes
}
Polynomail::result multiply(Polynomial &p, Polynomial &q)
{
int i, j, k = 0;
for(i = 0; i < p.val; i++)
{
for(j = 0; j < q.val; j++)
{
*poly->list[k] = new Node(0, 0);
*poly->list[k].coefficient = (p.poly->list[i].coefficient)*(q.poly->list[j].coefficient);
*poly->list[k++].power = (p.poly->list[i].power)+(q.poly->list[j].power);
}
}
val = k+1; //Store the nunber of nodes
return success;
}
Polynomial::void simplify(Polynomial &var)
{
int i, j, k = 0;
//Create a copy of the polynomial
for(j = 0; j < var.val; j++)
{
*poly->list[j] = new Node(0, 0);
*poly->list[j].coefficient = var.poly->list[j].coefficient;
*poly->list[j].power = var.poly->list[j].power;
}
//Iterate through the nodes to find entries which have the same power and add them, otherwise do nothing
for(k = 0; k < var.val; k++)
{
for(i = k; i < var.val;)
{
if(*poly->list[k].power == var.poly->list[++i].power)
{
if(*poly->list.power[0] == 0)
{
NULL;
}
else
{
*poly->list[k].coefficient = *poly->list[k].coefficient + var.poly->list[i].ceofficient;
var.poly->list[i] = Node(0, 0);
}
}
}
}
}
Polynomial::void print_pol()
{
int i = 0;
for(i = 0; i < temp.val; i++)
{
cout << "Coefficient: " << temp.poly->list[i].coefficient << ", and " << "Power: " << temp.poly->list[i].power << endl;
}
}
The problem is a wrong dereference. Line 34 should probably be
list[0] = NULL; // remove the *
You try to assign the value NULL to a variable of the type Node, but you probably mean a pointer to Node.
The very same is true in line 63.
In addition, line 66 sould probably b:
void Polynomial::initialize(ifstream &file) // start with return type