[education/rkward] rkward: Integer bsaed storage of value levels

Thomas Friedrichsmeier null at kde.org
Fri Sep 19 17:20:12 BST 2025


Git commit dab3aa29a33b0e8c15213642e24d2bfff935ff2c by Thomas Friedrichsmeier.
Committed on 19/09/2025 at 16:20.
Pushed by tfry into branch 'master'.

Integer bsaed storage of value levels

M  +20   -24   rkward/core/rkvariable.cpp
M  +2    -2    rkward/core/robject.h
M  +1    -1    rkward/misc/celleditor.cpp
M  +5    -5    rkward/misc/editlabelsdialog.cpp
M  +1    -1    rkward/misc/rktableview.cpp

https://invent.kde.org/education/rkward/-/commit/dab3aa29a33b0e8c15213642e24d2bfff935ff2c

diff --git a/rkward/core/rkvariable.cpp b/rkward/core/rkvariable.cpp
index afe6d87fe..2c1cd5ed0 100644
--- a/rkward/core/rkvariable.cpp
+++ b/rkward/core/rkvariable.cpp
@@ -230,7 +230,7 @@ void RKVariable::updateDataFromR(RCommandChain *chain) {
 			// no levels
 		} else {
 			for (int i = 0; i < levels_len; ++i) {
-				data->value_labels->insert(QString::number(i + 1), new_levels.at(i));
+				data->value_labels->insert(i + 1, new_levels.at(i));
 			}
 		}
 
@@ -471,9 +471,7 @@ QString RKVariable::getText(int row, bool pretty) const {
 			if (ret == QLatin1String("0")) return QStringLiteral("FALSE");
 			else if (ret == QLatin1String("1")) return QStringLiteral("TRUE");
 		} else if (data->value_labels) {
-			if (data->value_labels->contains(ret)) {
-				return (*(data->value_labels))[ret];
-			}
+			return data->value_labels->value(ret.toInt(), ret);
 		}
 	}
 	return ret;
@@ -522,10 +520,10 @@ void RKVariable::setText(int row, const QString &text) {
 			data->cell_strings[row] = text;
 		} else if (getDataType() == DataFactor) {
 			if (data->value_labels) {
-				QString realtext = data->value_labels->key(text); // first, attempt to set by level
-				if (!realtext.isEmpty()) data->cell_doubles[row] = realtext.toInt();
+				int key = data->value_labels->key(text, -1); // first, attempt to set by text
+				if (key >= 0) data->cell_doubles[row] = key;
 				else { // if this failed, try to set by index, instead.
-					if (data->value_labels->contains(text)) data->cell_doubles[row] = text.toInt();
+					if (data->value_labels->contains(text.toInt())) data->cell_doubles[row] = text.toInt();
 					else valid = false;
 				}
 			} else valid = false;
@@ -565,7 +563,7 @@ void RKVariable::setNumericFromR(int from_row, int to_row, const QVector<double>
 			if (data->cell_states[row] & RKVarEditData::Invalid) data->cell_states[row] = RKVarEditData::UnsyncedInvalidState;
 			else data->cell_states[row] = 0;
 
-			if (std::isnan(numdata[i]) || (!data->value_labels) || (!data->value_labels->contains(QString::number(numdata[i])))) {
+			if (std::isnan(numdata[i]) || (!data->value_labels) || (!data->value_labels->contains(numdata[i]))) {
 				data->cell_states[row] |= RKVarEditData::NA;
 			} else {
 				data->cell_states[row] |= RKVarEditData::Valid;
@@ -722,11 +720,11 @@ void RKVariable::updateValueLabels() {
 	// find out which values got valid / invalid and change those
 	for (int i = 0; i < getLength(); ++i) {
 		if (cellStatus(i) == ValueInvalid) {
-			if (labels && labels->contains(getText(i))) {
-				setText(i, getText(i));
+			if (labels && labels->key(data->invalid_fields.value(i), -1) >= 0) {
+				setText(i, data->invalid_fields.value(i));
 			}
 		} else {
-			if (!(labels && labels->contains(getText(i)))) {
+			if (!(labels && labels->key(getText(i), -1) >= 0)) {
 				setText(i, getText(i));
 			}
 		}
@@ -748,11 +746,10 @@ void RKVariable::writeValueLabels(RCommandChain *chain) const {
 	if (data->value_labels && (!data->value_labels->isEmpty())) {
 		int i = 1;
 		level_string = u"c ("_s;
-		while (data->value_labels->contains(QString::number(i))) {
-			level_string.append(rQuote((*(data->value_labels))[QString::number(i)]));
-			if (data->value_labels->contains(QString::number(++i))) {
-				level_string.append(u", "_s);
-			}
+		while (data->value_labels->contains(i)) {
+			if (i > 1) level_string.append(u", "_s);
+			level_string.append(rQuote((*(data->value_labels))[i]));
+			++i;
 		}
 		level_string.append(u')');
 	} else {
@@ -771,11 +768,10 @@ QString RKVariable::getValueLabelString() const {
 	if (data->value_labels) {
 		int i = 1;
 		QString level_string;
-		while (data->value_labels->contains(QString::number(i))) {
-			level_string.append((*(data->value_labels))[QString::number(i)]);
-			if (data->value_labels->contains(QString::number(++i))) {
-				level_string.append(u"#,#"_s);
-			}
+		while (data->value_labels->contains(i)) {
+			if (i > 1) level_string.append(u"#,#"_s);
+			level_string.append((*(data->value_labels))[i]);
+			++i;
 		}
 
 		return level_string;
@@ -789,11 +785,11 @@ void RKVariable::setValueLabelString(const QString &string) {
 	RK_ASSERT(data);
 
 	ValueLabels new_labels;
-	QStringList list = string.split(u"#,#"_s);
+	const QStringList list = string.split(u"#,#"_s);
 
 	int i = 1;
-	for (QStringList::const_iterator it = list.constBegin(); it != list.constEnd(); ++it) {
-		new_labels.insert(QString::number(i), *it);
+	for (const auto &lab : list) {
+		new_labels.insert(i, lab);
 		++i;
 	}
 	setValueLabels(new_labels);
diff --git a/rkward/core/robject.h b/rkward/core/robject.h
index f0e2f0ecf..88889aa62 100644
--- a/rkward/core/robject.h
+++ b/rkward/core/robject.h
@@ -178,9 +178,9 @@ class RObject {
 	/** A QList of RObjects. Internally the same as RObjectMap, but can be considered "public" */
 	typedef QList<RObject *> ObjectList;
 
-	// TODO: review whether we actually need string->string mapping at all, rather than just ordered (integer-indexed) list
+	// TODO: review whether we actually need mapping at all, rather than just ordered (integer-indexed) list
 	/** A map of values to labels. This is used both in regular objects, in which it just represents a map of named values, if any. The more important use is in factors, where it represents the factor levels. Here, the key is always a string representation of a positive integer. */
-	typedef QMap<QString, QString> ValueLabels;
+	typedef QMap<int, QString> ValueLabels;
 
 	/** write the MetaData to the backend. Commands will be issued in the given chain */
 	virtual void writeMetaData(RCommandChain *chain);
diff --git a/rkward/misc/celleditor.cpp b/rkward/misc/celleditor.cpp
index c3d2b3d3d..00d6db727 100644
--- a/rkward/misc/celleditor.cpp
+++ b/rkward/misc/celleditor.cpp
@@ -46,7 +46,7 @@ void CellEditor::setValueLabels(const RObject::ValueLabels &labels) {
 			value_list->addAction(i18n("[Omitted %1 more factor levels]", labels.size() - limit))->setEnabled(false);
 			break;
 		}
-		value_list->addAction(it.key().rightJustified(2) + u": "_s + it.value())->setData(it.key());
+		value_list->addAction(QString::number(it.key()).rightJustified(2) + u": "_s + it.value())->setData(it.key());
 	}
 	connect(value_list, &QMenu::triggered, this, &CellEditor::selectedFromList);
 
diff --git a/rkward/misc/editlabelsdialog.cpp b/rkward/misc/editlabelsdialog.cpp
index cbabcc5ff..81bd3d30a 100644
--- a/rkward/misc/editlabelsdialog.cpp
+++ b/rkward/misc/editlabelsdialog.cpp
@@ -142,7 +142,7 @@ QVariant RKVarLevelsTableModel::data(const QModelIndex &index, int role) const {
 	if ((role == Qt::BackgroundRole) && (index.row() == labels.count())) return QBrush(Qt::gray);
 	if (index.row() >= labels.count()) return QVariant();
 
-	if ((role == Qt::DisplayRole) || (role == Qt::EditRole)) return labels.value(QString::number(index.row() + 1));
+	if ((role == Qt::DisplayRole) || (role == Qt::EditRole)) return labels.value(index.row() + 1);
 
 	return QVariant();
 }
@@ -168,18 +168,18 @@ bool RKVarLevelsTableModel::setData(const QModelIndex &index, const QVariant &va
 	QString text = value.toString();
 	if (index.row() == labels.count()) {
 		beginInsertRows(QModelIndex(), index.row(), index.row());
-		labels.insert(QString::number(index.row() + 1), text);
+		labels.insert(index.row() + 1, text);
 		endInsertRows();
 	} else {
-		labels.insert(QString::number(index.row() + 1), text);
+		labels.insert(index.row() + 1, text);
 		Q_EMIT dataChanged(index, index);
 	}
 
 	if (text.isEmpty()) { // remove trailing empty rows
-		while ((!labels.isEmpty()) && labels.value(QString::number(labels.count())).isEmpty()) {
+		while ((!labels.isEmpty()) && labels.value(labels.count()).isEmpty()) {
 			int row = labels.count() - 1;
 			beginRemoveRows(QModelIndex(), row, row);
-			labels.remove(QString::number(row + 1));
+			labels.remove(row + 1);
 			endRemoveRows();
 		}
 	}
diff --git a/rkward/misc/rktableview.cpp b/rkward/misc/rktableview.cpp
index 18dd88f99..4912563ac 100644
--- a/rkward/misc/rktableview.cpp
+++ b/rkward/misc/rktableview.cpp
@@ -185,7 +185,7 @@ void RKItemDelegate::setEditorData(QWidget *editor, const QModelIndex &index) co
 			if (row == RKVarEditMetaModel::TypeRow) {
 				RObject::ValueLabels labels;
 				for (int i = RObject::MinKnownDataType; i <= RObject::MaxKnownDataType; ++i) {
-					labels.insert(QString::number(i), RObject::typeToText((RObject::RDataType)i));
+					labels.insert(i, RObject::typeToText((RObject::RDataType)i));
 				}
 				ced->setValueLabels(labels);
 			}


More information about the rkward-tracker mailing list