# Building a distance matrix

I came across an interesting exercise that I would like to try to solve with Mathematica to improve my skills. In data is provided to build a distance matrix. The data looks like this, starting from node0 to node99:

node0, node1 0.04, node8 11.11, node14 72.21
node1, node46 1247.25, node6 20.59, node13 64.94
node2, node66 54.18, node31 166.80, node45 1561.45
node3, node20 133.65, node6 2.06, node11 42.43


I was just wondering how would you start doing this. I imported the file using Import["file.txt", "Data"]. I've been trying to make strings of each line and to drop the 1st element of the string, but I can't seem to get this. I started by doing:

number_nodes=100
max_node=99
data= Import["file.txt", "Data"]


Currently stuck at this stage Any help would be greatly appreciated :)

• Welcome to the Mathematica Stack Exchange. Please include Mathematica code that you have tried out so far.
– Syed
Feb 21, 2022 at 18:25
• My initial code edited on the main question. But its not much im stuck at the start :( Feb 21, 2022 at 18:55
• Here's a starting point: data = ImportString["paste_given_data_here", "Table", "FieldSeparators" -> {",", " ", "node"}]. Since in Mathematica lists start at index 1, not 0, you can then adjust the node numbers by adding 1 to any integer in the results: data /. a_Integer :> a + 1. I have to say, though, that the format in that exercise is rather awful to work with. Feb 21, 2022 at 19:12
• So right now I have the code n = 100; max_number = 99; Q = ConstantArray[Infinity, {n, n}]; Q // MatrixForm; data = ImportString["data", "Table", "FieldSeparators" -> {",", " ", "node"}]; node = Drop[data, 0, 1]. Is this good? Im planning to make this an interfer this run a if loop and fill the matrix i made. Feb 21, 2022 at 21:09
• The "Accepted" (an answer) status indicates that the question has been answered. Please do not try to erase the question. The purpose of SE is to be a repository of Q&A as resource for others. Mar 10, 2022 at 1:40

Note that there may be some mistakes in this solution, but it should give you a general idea and you can fix mistakes if you find any. Here is how I did it: I downloaded and saved the file as "temp.txt" in my working directory. Then I read the file and remove the first line:

graph = ReadList["temp.txt", String]
graph = Rest[graph];


Then I extracted the distances by cleaning up the text and splitting at spaces or commas:

dists = Table[
Cases[ToExpression[StringSplit[graph[[i]], Whitespace | "," ]], _?
NumericQ], {i, Length@graph}]


Then I got the connectivity by first finding all the instances of "node", made them numbers using ToExpression' and added 1 to adjust from zero based arrays in Python:

nodeslist =
ToExpression@
Table[StringCases[graph[[i]],
"node" ~~ x : RegularExpression["\\d+"] -> x], {i,
Length@graph}] + 1


The first instance of node in each of these is basically the node number, therefore it is easier to remove it. Also, some nodes like the last one (node99 in the original file) are not connected to any other nodes and are empty. So I removed them:

connectivity = Rest /@ nodeslist /. {} -> Nothing


Then I created assignment rules and created a sparse array:

arrayrules =
Table[{i, connectivity[[i, j]]} -> dists[[i, j]], {j, 1,
Length@connectivity[[i]]}, {i, n - 1}];

mat=SparseArray[arrayrules[], {100, 100}]


You can convert back to a normal matrix using Normal and visualize it:

mat// Normal // MatrixForm


Also using MatrixPlot: • Thank you very much :) Feb 21, 2022 at 23:46
M = Array[m, {100, 100}]; (*the matrix; placeholder for its entries;*)
list = Import["graph.txt", "CSV"]; (*import the source data*)
graph = ToExpression[StringSplit[#] & /@ list]; (*reformat list to mathematica-friendly*)
node = Table[ToExpression["node" <> ToString[i]], {i, 0, 99}]; (*node variable naming*)
igraph = graph /. MapThread[(#1 -> #2) &, {node, Range[1, 100]}]; (*node variable indexification*)

(*igraph to graph-friendly structure; {i,j,m[i,j]}, m[i,j] is the dist btwn i & j*)
dist = Select[Flatten[Module[{x},
x = #;
Join[x[], #] & /@ x[[2 ;; -1]]
] & /@ igraph, 1], Length@# > 1 &];

(*assign dist to the pairs*)
MapThread[(#1 = #2) &, {Map[Extract[M, #] &, dist[[All, 1 ;; 2]]], dist[[All, 3]]}];
(*assign string "." to the pairs without value*)
Map[If[Not[NumberQ[#]], # = "."] &, Flatten@M];

(*output first 10x10 of M*)
MatrixForm@M[[1 ;; 10, 1 ;; 10]] If you expect the graph to be undirected, use the following dist instead:

dist = Flatten[Select[Flatten[Module[{x},
x = #;
Join[x[], #] & /@ x[[2 ;; -1]]
] & /@ igraph, 1], Length@# > 1 &] /. {i_, j_, v_} -> {{i, j, v}, {j, i, v}}, 1]; --

Please feel free to take a look inside and play with the code. Note that though, if you execute the value assigning lines (MapThread) again after once it's executed, it will cause error because once you assign, it gets protected. In such case, clear the definitions.

• @djxdddd I'd suspect that you didn't import the file properly, because I see you named your file as file.txt while I named graph.txt. Also, put the file in the same folder with the notebook file and set SetDirectory[NotebookDirectory[]]. Feb 21, 2022 at 23:34
• @djxdddd That's because m's were already assigned somewhere, like I mentioned. You could try <code>ClearAll["Global*"]</code> to clear the definitions and execute fresh. Feb 21, 2022 at 23:49
• @djxdddd YOU ARE WELCOME! Feb 21, 2022 at 23:58