It does have to map 1 to 1 with the layout, indeed. But the pSysMem pointer doesn't have to be an array (or pointer) of type SVertex. You can create a byte array and fill it using the same method I used in the aforementioned example. You can use assimp's aiMesh to check if the layout has the position, normal, and so on and add them to the array of bytes in the same order as you did in the input layout.
I hope that suits your needs. Here is quick&dirty example (don't use it directly, it's just to show how it would work, I didnt try to compile it):
HRESULT SMesh::CreateVB(ID3D11DeviceContext* dc, ID3D11Device* device, aiMesh * mesh)
{
HRESULT hr;
int singleVertexSize = 3*3; // in bytes (x,y,z = 3 floats); always has position, so no need to check that
if (mesh->HasNormals()) singleVertexSize += 3*3; // x,y,z = 3 floats
if (mesh->HasTexCoords()) singleVertexSize += 2*3; // u,v = 2 floats
ZeroMemory( &bufferDesc, sizeof(bufferDesc) );
bufferDesc.Usage = D3D11_USAGE_DEFAULT;
bufferDesc.ByteWidth = singleVertexSize * mesh->mNumVertices;
bufferDesc.BindFlags = D3D11_BIND_VERTEX_BUFFER;
bufferDesc.CPUAccessFlags = 0;
bufferDesc.MiscFlags = 0;
vertexCount = mesh->mNumVertices;
char * pmem = new char[singleVertexSize];
float * fp;
for (int i = 0; i < mesh->mNumVertices; ++i)
{
fp = (float*)pmem;
*fp = mesh->mVertices[i].x;
*(fp+1) = mesh->mVertices[i].y;
*(fp+2) = mesh->mVertices[i].z;
if (mesh->HasNormals())
{
*(fp+3) = mesh->mNormals[i].x;
*(fp+4) = mesh->mNormals[i].y;
*(fp+5) = mesh->mNormals[i].z;
}
if (mesh->HasTexCoords())
{
*(fp+6) = mesh->mTexCoords[i].u;
*(fp+7) = mesh->mTexCoords[i].v;
}
pmem += singleVertexSize;
}
//ZeroMemory( &InitData, sizeof(InitData) ); not really needed, you fill all members below explicitly..
InitData.pSysMem = pmem;
InitData.SysMemPitch = 0;
InitData.SysMemSlicePitch = 0;
hr = device->CreateBuffer( &bufferDesc, &InitData, &vertexBuffer[0] );
delete [] pmem;
return hr;
}