0
$\begingroup$

So, I read a set of variables and respective values from a file and store them in a variable

specs = {{"Type", "KP", "fp"}, {"LP1", 2, 2000}, {"Type", "KP", "fp", "Qp"}, {"LP2", 4, 1000, 3}}

Each pair of variables/specs shall be treated separately. Also depending on the file this fields might change both names and variables. This creates a problem because I basically lose the name of the variables.

I try to do

For[i = 1, i <= Length[specs], i = i + 2, Evaluate[ToExpression[specs[[i]]]]=specs[[i+1]] ];

And while the first iteration goes well, the second iteration gets me

Set::setraw: Cannot assign to raw object LP1. Set::setraw: Cannot assign to raw object 2. Set::setraw: Cannot assign to raw object 2000.

And of course that is because "Type", "KP", "fp" were assigned to "LP1", 2, 2000 in the first iteration and now can't be evaluated again. Any smart way to fix this? Again I can't specifically put on the code Clear[Type, KP, fP] as the variables might change their names in other files. This is supposed to be robust to that level.

Thank you.

$\endgroup$
6
  • $\begingroup$ What is the desired output? $\endgroup$
    – Syed
    Commented Apr 10, 2023 at 4:48
  • $\begingroup$ I will just use these variables to obtain a transfer function, save that, and discard the variables. $\endgroup$ Commented Apr 10, 2023 at 4:56
  • $\begingroup$ That is not the desired output. This is what you intend to do with the desired output. $\endgroup$
    – Syed
    Commented Apr 10, 2023 at 4:57
  • 3
    $\begingroup$ If you reassign the same variable in a loop it will be overwritten. You can instead get a list of rules and use them later; e.g., {{Type -> "LP1", KP -> 2, fp -> 2000}, {Type -> "LP2", KP -> 4, fp -> 1000, Qp -> 3}} $\endgroup$
    – Syed
    Commented Apr 10, 2023 at 5:07
  • 2
    $\begingroup$ I agree with @Syed that a bit of pre-processing could be good, depending on use-case: Transpose /@ Partition[specs, 2] (generating lists) or Thread@*Rule @@@ Partition[specs, 2] (generating rules) or Association@*Thread@*Rule @@@ Partition[specs, 2] (generating associations). $\endgroup$
    – Roman
    Commented Apr 10, 2023 at 6:44

3 Answers 3

1
$\begingroup$

Here's a possible strategy based on

the desired output is the variables in the ith position with the values of the (i+1)th position attributed to them

We can get a pretty raw and basic representation of that with this:

Thread /@ Partition[specs, 2]

{{{"Type", "LP1"}, {"KP", 2}, {"fp", 2000}}, {{"Type", "LP2"}, {"KP", 4}, {"fp", 1000}, {"Qp", 3}}}

We have two elements, and each consists of a list of pairs. Each pair corresponds to a variable name and a value. Maybe that's enough for you. But we could add more structure.

Apply[Rule, Thread /@ Partition[specs, 2], {2}]

{{"Type" -> "LP1", "KP" -> 2, "fp" -> 2000}, {"Type" -> "LP2", "KP" -> 4, "fp" -> 1000, "Qp" -> 3}}

This does a bit more to imply the semantics. We now have two elements that each consist of a list of rules of the form var -> val. With such rule lists you could easily do substitutions. You could take advantage of further built-in data-handling functionality with associations.

Association @@@ Apply[Rule, Thread /@ Partition[specs, 2], {2}]

{<|"Type" -> "LP1", "KP" -> 2, "fp" -> 2000|>, <|"Type" -> "LP2", "KP" -> 4, "fp" -> 1000, "Qp" -> 3|>}

You could even use datasets, but it sounds like your context doesn't really need to go that far. (You can find alternate code samples in the comments that achieve the same result.)

Now, how you process these structures depends on your context, so maybe we can take this further with more information.

$\endgroup$
1
$\begingroup$

Avoid the problem entirely by using instead of fighting Mathematica. In the following example code, the first parameter of the Table command is where the code goes to process your $\text{specs}$ in the Mathematica form and the second parameter of the Table modifies the original $\text{specs}$ into s more convenient form for Mathematica.

Now, consider the following:

  1. Do not use ToExpression on strings that you do not control absolutely. ToExpression easily leads to arbitary code execution on your computer.

  2. In this case, by using ToExpression, you attacked yourself by creating symbols that conflicted later.

  3. An Association (<||>) is a hash table and it associates keys with values. Since I have no idea of you are trying to do, the Print statements in the first Table parameter are a stand-in for whatever your program may be.

  4. What are the most common pitfalls awaiting new users?

  5. How to copy code from Mathematica so it looks good on this site.

  6. The Internals of the Wolfram System. This document is not all that deep.

$\endgroup$
0
$\begingroup$

The problem is that strings are raw object which cannot Set. So the right hand string has to be converted to an expression. But Type cannot be set, too, because its a protected symbol. The other problem is, that immediate setting of the same object to different values would result in overwriting the result of the first setting.

So there is no other way as to generate a list of replacement rules for the strings or alter them to lower case symbols, that can be used anywhere in expression to replace the strings on the left by the actual values on the right in this table.

( Transpose /@ {{{"type", "KP", "fp"}, {"LP1", 2, 2000}}, {{"type", "KP", "fp", "Qp"}, {"LP2", 4, 1000, 3}}}) /. '{{a_String, b_ } :> Rule @@ { ToExpression[a] , b}}

It is of course much more practical and readable to write a simple expanded list of replacement rules directly.

{{type-> "LP1", kp->2, fp->2000}, {type-> "LP2", kp-> 4, fp-> 1000, qp-> 3}}

Depending on the goal these set of rule generate two sets of values. Without the intended use of these settings nothing more can be said.

$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.